From fe622654e51bbc556dfc320fc0578117c05ffa8c Mon Sep 17 00:00:00 2001 From: Masashi Date: Mon, 15 Dec 2025 18:20:53 +0530 Subject: [PATCH] pointers pointers pointers --- src/ast.rs | 11 ++++++++- src/lexer/mod.rs | 3 +++ src/lexer/tests.rs | 3 ++- src/monomorphize.rs | 13 ++++++++++ src/parser.rs | 27 +++++++++++++++++++++ src/typechecker.rs | 29 ++++++++++++++++++++++ syntax_test.sui | 4 ---- tests/comprehensive_pointers.sui | 41 ++++++++++++++++++++++++++++++++ tests/pointers.sui | 6 +++++ 9 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 tests/comprehensive_pointers.sui create mode 100644 tests/pointers.sui diff --git a/src/ast.rs b/src/ast.rs index fe65eb3..616ab90 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -11,6 +11,7 @@ pub enum TypeAnnot { Function(Vec, Box), Tuple(Vec), Array(Box), + Ptr(Box), } #[derive(Debug, Clone)] @@ -264,6 +265,8 @@ pub enum BinOp { pub enum UnOp { Neg, Not, + Ref, + Deref, } #[derive(Debug, Clone)] @@ -399,7 +402,13 @@ pub enum TypedExprKind { EarlyReturn(Option>), OptionalChain(Option>, String), Lambda(Vec<(BindingId, String, Option)>, Box), - Let(BindingId, String, BindingKind, Option, Box), + Let( + BindingId, + String, + BindingKind, + Option, + Box, + ), Assign(Box, Box), Cast(Box, TypeAnnot), If(Box, Box, Option>), diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index 4467413..76c1f6d 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -174,6 +174,9 @@ pub enum Token { #[token("@")] At, + #[token("&")] + Amp, + #[token("==")] Eq, diff --git a/src/lexer/tests.rs b/src/lexer/tests.rs index 1799148..6e03c88 100644 --- a/src/lexer/tests.rs +++ b/src/lexer/tests.rs @@ -121,7 +121,7 @@ fn test_assignment_operators() { #[test] fn test_punctuation() { - let mut lexer = Token::lexer("( ) [ ] { } , ; : . ... .. :: -> ~ ! => | |> ?. ?"); + let mut lexer = Token::lexer("( ) [ ] { } , ; : . ... .. :: -> ~ ! => & | ?. ?"); assert_eq!(lexer.next(), Some(Ok(Token::LParen))); assert_eq!(lexer.next(), Some(Ok(Token::RParen))); @@ -140,6 +140,7 @@ fn test_punctuation() { assert_eq!(lexer.next(), Some(Ok(Token::Tilde))); assert_eq!(lexer.next(), Some(Ok(Token::Bang))); assert_eq!(lexer.next(), Some(Ok(Token::FatArrow))); + assert_eq!(lexer.next(), Some(Ok(Token::Amp))); assert_eq!(lexer.next(), Some(Ok(Token::Union))); assert_eq!(lexer.next(), Some(Ok(Token::OptionalChain))); assert_eq!(lexer.next(), Some(Ok(Token::Unwrap))); diff --git a/src/monomorphize.rs b/src/monomorphize.rs index bbd9e0e..a064b15 100644 --- a/src/monomorphize.rs +++ b/src/monomorphize.rs @@ -757,6 +757,10 @@ impl Monomorphizer { let new_inner = self.substitute_in_type_annot(inner, subst_map)?; Ok(TypeAnnot::Array(Box::new(new_inner))) } + TypeAnnot::Ptr(inner) => { + let new_inner = self.substitute_in_type_annot(inner, subst_map)?; + Ok(TypeAnnot::Ptr(Box::new(new_inner))) + } } } @@ -768,6 +772,7 @@ impl Monomorphizer { Type::String => TypeAnnot::Var("string".to_string()), Type::Unit => TypeAnnot::Tuple(Vec::new()), Type::Array(inner) => TypeAnnot::Array(Box::new(self.type_to_type_annot(inner))), + Type::Ptr(inner) => TypeAnnot::Ptr(Box::new(self.type_to_type_annot(inner))), Type::Tuple(types) => { let annots = types.iter().map(|t| self.type_to_type_annot(t)).collect(); TypeAnnot::Tuple(annots) @@ -886,6 +891,9 @@ impl Monomorphizer { TypeAnnot::Array(inner) => { self.collect_needs_from_type(inner, needs); } + TypeAnnot::Ptr(inner) => { + self.collect_needs_from_type(inner, needs); + } } } @@ -918,6 +926,10 @@ impl Monomorphizer { let inner_type = self.type_annot_to_type(inner); Type::Array(Box::new(inner_type)) } + TypeAnnot::Ptr(inner) => { + let inner_type = self.type_annot_to_type(inner); + Type::Ptr(Box::new(inner_type)) + } } } @@ -1194,5 +1206,6 @@ fn has_typevars_in_type_annot(ty: &TypeAnnot) -> bool { } TypeAnnot::Tuple(types) => types.iter().any(has_typevars_in_type_annot), TypeAnnot::Array(inner) => has_typevars_in_type_annot(inner), + TypeAnnot::Ptr(inner) => has_typevars_in_type_annot(inner), } } diff --git a/src/parser.rs b/src/parser.rs index 9173085..db7026b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -690,6 +690,13 @@ impl Parser { fn parse_type_annot(&mut self) -> Result { let start = self.peek_span().unwrap_or(0..0).start; + // Check for pointer type: *T + if matches!(self.peek(), Some(Token::Mul)) { + self.next(); + let inner = self.parse_type_annot()?; + return Ok(TypeAnnot::Ptr(Box::new(inner))); + } + // Check for function type: fn (args)->ret if matches!(self.peek(), Some(Token::KeywordFn)) { self.next(); @@ -1052,6 +1059,26 @@ impl Parser { attributes: Vec::new(), }) } + Some(Token::Amp) => { + self.next(); + let expr = self.parse_unary_expr()?; + let end = expr.span.end; + Ok(Expr { + kind: ExprKind::UnOp(UnOp::Ref, Box::new(expr)), + span: Span::new(&(start..end), self.file.clone()), + attributes: Vec::new(), + }) + } + Some(Token::Mul) => { + self.next(); + let expr = self.parse_unary_expr()?; + let end = expr.span.end; + Ok(Expr { + kind: ExprKind::UnOp(UnOp::Deref, Box::new(expr)), + span: Span::new(&(start..end), self.file.clone()), + attributes: Vec::new(), + }) + } _ => self.parse_postfix_expr(), } } diff --git a/src/typechecker.rs b/src/typechecker.rs index ae4b82d..26f904b 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -11,6 +11,7 @@ pub enum Type { Unit, Never, Array(Box), + Ptr(Box), Tuple(Vec), Function(Vec, Box), Struct(String, Vec), // name and type arguments @@ -30,6 +31,7 @@ impl Type { Type::Unit => "()".to_string(), Type::Never => "!".to_string(), Type::Array(inner) => format!("[{}]", inner.to_string()), + Type::Ptr(inner) => format!("*{}", inner.to_string()), Type::Tuple(types) => { let type_strs: Vec = types.iter().map(|t| t.to_string()).collect(); format!("({})", type_strs.join(", ")) @@ -733,6 +735,25 @@ impl TypeChecker { } Type::Bool } + UnOp::Ref => { + // &expr creates a pointer to expr + Type::Ptr(Box::new(typed_inner.ty.clone())) + } + UnOp::Deref => { + // *expr dereferences a pointer + match &typed_inner.ty { + Type::Ptr(inner_ty) => (**inner_ty).clone(), + _ => { + return Err(TypeError { + kind: TypeErrorKind::TypeMismatch( + Type::Ptr(Box::new(Type::Unknown)), + typed_inner.ty.clone(), + ), + span: inner.span.clone(), + }); + } + } + } }; ( TypedExprKind::UnOp(op.clone(), Box::new(typed_inner)), @@ -1322,6 +1343,9 @@ impl TypeChecker { (TypeAnnot::Array(inner), Type::Array(actual_inner)) => { self.infer_type_args(inner, actual_inner, type_params, type_map); } + (TypeAnnot::Ptr(inner), Type::Ptr(actual_inner)) => { + self.infer_type_args(inner, actual_inner, type_params, type_map); + } (TypeAnnot::Tuple(expected_types), Type::Tuple(actual_types)) => { for (e, a) in expected_types.iter().zip(actual_types.iter()) { self.infer_type_args(e, a, type_params, type_map); @@ -1605,6 +1629,9 @@ impl TypeChecker { TypeAnnot::Array(inner) => { Type::Array(Box::new(self.substitute_type(inner, subst_map))) } + TypeAnnot::Ptr(inner) => { + Type::Ptr(Box::new(self.substitute_type(inner, subst_map))) + } TypeAnnot::Tuple(types) => { let substituted_types: Vec = types .iter() @@ -1677,6 +1704,7 @@ impl TypeChecker { Type::Tuple(tuple_types) } TypeAnnot::Array(inner) => Type::Array(Box::new(self.type_annot_to_type(inner))), + TypeAnnot::Ptr(inner) => Type::Ptr(Box::new(self.type_annot_to_type(inner))), } } @@ -1690,6 +1718,7 @@ impl TypeChecker { (Type::Unit, Type::Unit) => true, (Type::Never, _) | (_, Type::Never) => true, (Type::Array(a), Type::Array(b)) => self.types_compatible(a, b), + (Type::Ptr(a), Type::Ptr(b)) => self.types_compatible(a, b), (Type::Tuple(a), Type::Tuple(b)) => { a.len() == b.len() && a.iter() diff --git a/syntax_test.sui b/syntax_test.sui index 2ae3334..0db6f6a 100644 --- a/syntax_test.sui +++ b/syntax_test.sui @@ -127,7 +127,6 @@ fn process_list(items: int) -> int do result + items end - fn literals() -> bool do let int_val = 42 let float_val = 3.14 @@ -140,7 +139,6 @@ fn literals() -> bool do true end - fn collections() -> bool do let arr = [1, 2, 3, 4, 5] let empty_arr = [] @@ -149,7 +147,6 @@ fn collections() -> bool do true end - fn struct_enum_literals() -> bool do let point = Point { x: 10, y: 20 } let option_val = Option::Some(42) @@ -160,7 +157,6 @@ fn struct_enum_literals() -> bool do true end - fn arithmetic_logic() -> int do let a = 10 let b = 5 diff --git a/tests/comprehensive_pointers.sui b/tests/comprehensive_pointers.sui new file mode 100644 index 0000000..a2c9021 --- /dev/null +++ b/tests/comprehensive_pointers.sui @@ -0,0 +1,41 @@ +# Pointer in struct +struct Point + x: *int, + y: int, +end + + # Pointer in function parameter +fn take_ptr(ptr: *int) -> int do + 0 # dummy +end + +# Pointer in return type +fn return_ptr(x: int) -> *int do + x as *int +end + +fn main() -> int do + # Basic pointer + let x: *int = 0 as *int; + let y = x; # Should infer *int + + # Reference and dereference + let val = 42; + let ptr = &val; # Should be *int + let deref_val = *ptr; # Should be int + + let ptr_to_ptr: *(*int) = &ptr; # **int + + let p = Point { x: ptr, y: 42 }; + + take_ptr(ptr); + + let z = return_ptr(deref_val); + + # Nested operations + let nested_ptr = &ptr; # **int + let deref_once = *nested_ptr; # *int + let deref_twice = *deref_once; # int + + 42 +end diff --git a/tests/pointers.sui b/tests/pointers.sui new file mode 100644 index 0000000..cbf885d --- /dev/null +++ b/tests/pointers.sui @@ -0,0 +1,6 @@ +# Pointer type test +fn main() -> int do + let x: *int = 0 as *int; # Cast to pointer for now + let y = x; # Should infer *int + 42 +end \ No newline at end of file