Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
872c8e356d
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>),
|
||||
Tuple(Vec<TypeAnnot>),
|
||||
Array(Box<TypeAnnot>),
|
||||
Ptr(Box<TypeAnnot>),
|
||||
}
|
||||
|
||||
#[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<Box<TypedExpr>>),
|
||||
OptionalChain(Option<Box<TypedExpr>>, String),
|
||||
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>),
|
||||
Cast(Box<TypedExpr>, TypeAnnot),
|
||||
If(Box<TypedExpr>, Box<TypedExpr>, Option<Box<TypedExpr>>),
|
||||
|
|
|
|||
|
|
@ -174,6 +174,9 @@ pub enum Token {
|
|||
#[token("@")]
|
||||
At,
|
||||
|
||||
#[token("&")]
|
||||
Amp,
|
||||
|
||||
#[token("==")]
|
||||
Eq,
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -690,6 +690,13 @@ impl Parser {
|
|||
fn parse_type_annot(&mut self) -> Result<TypeAnnot, ParseError> {
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub enum Type {
|
|||
Unit,
|
||||
Never,
|
||||
Array(Box<Type>),
|
||||
Ptr(Box<Type>),
|
||||
Tuple(Vec<Type>),
|
||||
Function(Vec<Type>, Box<Type>),
|
||||
Struct(String, Vec<Type>), // 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<String> = 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<Type> = 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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
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