pointers pointers pointers
This commit is contained in:
parent
b959e11e51
commit
fe622654e5
9 changed files with 131 additions and 6 deletions
11
src/ast.rs
11
src/ast.rs
|
|
@ -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>>),
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,9 @@ pub enum Token {
|
||||||
#[token("@")]
|
#[token("@")]
|
||||||
At,
|
At,
|
||||||
|
|
||||||
|
#[token("&")]
|
||||||
|
Amp,
|
||||||
|
|
||||||
#[token("==")]
|
#[token("==")]
|
||||||
Eq,
|
Eq,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)));
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
41
tests/comprehensive_pointers.sui
Normal file
41
tests/comprehensive_pointers.sui
Normal 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
6
tests/pointers.sui
Normal 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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue