pointers pointers pointers

This commit is contained in:
Masashi 2025-12-15 18:20:53 +05:30
commit fe622654e5
9 changed files with 131 additions and 6 deletions

View file

@ -11,6 +11,7 @@ pub enum TypeAnnot {
Function(Vec<TypeAnnot>, Box<TypeAnnot>), Function(Vec<TypeAnnot>, Box<TypeAnnot>),
Tuple(Vec<TypeAnnot>), Tuple(Vec<TypeAnnot>),
Array(Box<TypeAnnot>), Array(Box<TypeAnnot>),
Ptr(Box<TypeAnnot>),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -264,6 +265,8 @@ pub enum BinOp {
pub enum UnOp { pub enum UnOp {
Neg, Neg,
Not, Not,
Ref,
Deref,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -399,7 +402,13 @@ pub enum TypedExprKind {
EarlyReturn(Option<Box<TypedExpr>>), EarlyReturn(Option<Box<TypedExpr>>),
OptionalChain(Option<Box<TypedExpr>>, String), OptionalChain(Option<Box<TypedExpr>>, String),
Lambda(Vec<(BindingId, String, Option<TypeAnnot>)>, Box<TypedExpr>), Lambda(Vec<(BindingId, String, Option<TypeAnnot>)>, Box<TypedExpr>),
Let(BindingId, String, BindingKind, Option<TypeAnnot>, Box<TypedExpr>), Let(
BindingId,
String,
BindingKind,
Option<TypeAnnot>,
Box<TypedExpr>,
),
Assign(Box<TypedExpr>, Box<TypedExpr>), Assign(Box<TypedExpr>, Box<TypedExpr>),
Cast(Box<TypedExpr>, TypeAnnot), Cast(Box<TypedExpr>, TypeAnnot),
If(Box<TypedExpr>, Box<TypedExpr>, Option<Box<TypedExpr>>), If(Box<TypedExpr>, Box<TypedExpr>, Option<Box<TypedExpr>>),

View file

@ -174,6 +174,9 @@ pub enum Token {
#[token("@")] #[token("@")]
At, At,
#[token("&")]
Amp,
#[token("==")] #[token("==")]
Eq, Eq,

View file

@ -121,7 +121,7 @@ fn test_assignment_operators() {
#[test] #[test]
fn test_punctuation() { 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::LParen)));
assert_eq!(lexer.next(), Some(Ok(Token::RParen))); 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::Tilde)));
assert_eq!(lexer.next(), Some(Ok(Token::Bang))); assert_eq!(lexer.next(), Some(Ok(Token::Bang)));
assert_eq!(lexer.next(), Some(Ok(Token::FatArrow))); 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::Union)));
assert_eq!(lexer.next(), Some(Ok(Token::OptionalChain))); assert_eq!(lexer.next(), Some(Ok(Token::OptionalChain)));
assert_eq!(lexer.next(), Some(Ok(Token::Unwrap))); assert_eq!(lexer.next(), Some(Ok(Token::Unwrap)));

View file

@ -757,6 +757,10 @@ impl Monomorphizer {
let new_inner = self.substitute_in_type_annot(inner, subst_map)?; let new_inner = self.substitute_in_type_annot(inner, subst_map)?;
Ok(TypeAnnot::Array(Box::new(new_inner))) 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::String => TypeAnnot::Var("string".to_string()),
Type::Unit => TypeAnnot::Tuple(Vec::new()), Type::Unit => TypeAnnot::Tuple(Vec::new()),
Type::Array(inner) => TypeAnnot::Array(Box::new(self.type_to_type_annot(inner))), 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) => { Type::Tuple(types) => {
let annots = types.iter().map(|t| self.type_to_type_annot(t)).collect(); let annots = types.iter().map(|t| self.type_to_type_annot(t)).collect();
TypeAnnot::Tuple(annots) TypeAnnot::Tuple(annots)
@ -886,6 +891,9 @@ impl Monomorphizer {
TypeAnnot::Array(inner) => { TypeAnnot::Array(inner) => {
self.collect_needs_from_type(inner, needs); 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); let inner_type = self.type_annot_to_type(inner);
Type::Array(Box::new(inner_type)) 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::Tuple(types) => types.iter().any(has_typevars_in_type_annot),
TypeAnnot::Array(inner) => has_typevars_in_type_annot(inner), TypeAnnot::Array(inner) => has_typevars_in_type_annot(inner),
TypeAnnot::Ptr(inner) => has_typevars_in_type_annot(inner),
} }
} }

View file

@ -690,6 +690,13 @@ impl Parser {
fn parse_type_annot(&mut self) -> Result<TypeAnnot, ParseError> { fn parse_type_annot(&mut self) -> Result<TypeAnnot, ParseError> {
let start = self.peek_span().unwrap_or(0..0).start; 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 // Check for function type: fn (args)->ret
if matches!(self.peek(), Some(Token::KeywordFn)) { if matches!(self.peek(), Some(Token::KeywordFn)) {
self.next(); self.next();
@ -1052,6 +1059,26 @@ impl Parser {
attributes: Vec::new(), 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(), _ => self.parse_postfix_expr(),
} }
} }

View file

@ -11,6 +11,7 @@ pub enum Type {
Unit, Unit,
Never, Never,
Array(Box<Type>), Array(Box<Type>),
Ptr(Box<Type>),
Tuple(Vec<Type>), Tuple(Vec<Type>),
Function(Vec<Type>, Box<Type>), Function(Vec<Type>, Box<Type>),
Struct(String, Vec<Type>), // name and type arguments Struct(String, Vec<Type>), // name and type arguments
@ -30,6 +31,7 @@ impl Type {
Type::Unit => "()".to_string(), Type::Unit => "()".to_string(),
Type::Never => "!".to_string(), Type::Never => "!".to_string(),
Type::Array(inner) => format!("[{}]", inner.to_string()), Type::Array(inner) => format!("[{}]", inner.to_string()),
Type::Ptr(inner) => format!("*{}", inner.to_string()),
Type::Tuple(types) => { Type::Tuple(types) => {
let type_strs: Vec<String> = types.iter().map(|t| t.to_string()).collect(); let type_strs: Vec<String> = types.iter().map(|t| t.to_string()).collect();
format!("({})", type_strs.join(", ")) format!("({})", type_strs.join(", "))
@ -733,6 +735,25 @@ impl TypeChecker {
} }
Type::Bool 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)), TypedExprKind::UnOp(op.clone(), Box::new(typed_inner)),
@ -1322,6 +1343,9 @@ impl TypeChecker {
(TypeAnnot::Array(inner), Type::Array(actual_inner)) => { (TypeAnnot::Array(inner), Type::Array(actual_inner)) => {
self.infer_type_args(inner, actual_inner, type_params, type_map); 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)) => { (TypeAnnot::Tuple(expected_types), Type::Tuple(actual_types)) => {
for (e, a) in expected_types.iter().zip(actual_types.iter()) { for (e, a) in expected_types.iter().zip(actual_types.iter()) {
self.infer_type_args(e, a, type_params, type_map); self.infer_type_args(e, a, type_params, type_map);
@ -1605,6 +1629,9 @@ impl TypeChecker {
TypeAnnot::Array(inner) => { TypeAnnot::Array(inner) => {
Type::Array(Box::new(self.substitute_type(inner, subst_map))) 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) => { TypeAnnot::Tuple(types) => {
let substituted_types: Vec<Type> = types let substituted_types: Vec<Type> = types
.iter() .iter()
@ -1677,6 +1704,7 @@ impl TypeChecker {
Type::Tuple(tuple_types) Type::Tuple(tuple_types)
} }
TypeAnnot::Array(inner) => Type::Array(Box::new(self.type_annot_to_type(inner))), 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::Unit, Type::Unit) => true,
(Type::Never, _) | (_, Type::Never) => true, (Type::Never, _) | (_, Type::Never) => true,
(Type::Array(a), Type::Array(b)) => self.types_compatible(a, b), (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)) => { (Type::Tuple(a), Type::Tuple(b)) => {
a.len() == b.len() a.len() == b.len()
&& a.iter() && a.iter()

View file

@ -127,7 +127,6 @@ fn process_list(items: int) -> int do
result + items result + items
end end
fn literals() -> bool do fn literals() -> bool do
let int_val = 42 let int_val = 42
let float_val = 3.14 let float_val = 3.14
@ -140,7 +139,6 @@ fn literals() -> bool do
true true
end end
fn collections() -> bool do fn collections() -> bool do
let arr = [1, 2, 3, 4, 5] let arr = [1, 2, 3, 4, 5]
let empty_arr = [] let empty_arr = []
@ -149,7 +147,6 @@ fn collections() -> bool do
true true
end end
fn struct_enum_literals() -> bool do fn struct_enum_literals() -> bool do
let point = Point { x: 10, y: 20 } let point = Point { x: 10, y: 20 }
let option_val = Option::Some(42) let option_val = Option::Some(42)
@ -160,7 +157,6 @@ fn struct_enum_literals() -> bool do
true true
end end
fn arithmetic_logic() -> int do fn arithmetic_logic() -> int do
let a = 10 let a = 10
let b = 5 let b = 5

View file

@ -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

6
tests/pointers.sui Normal file
View file

@ -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