Compare commits
3 commits
ad868c0c25
...
22afdb20a4
| Author | SHA1 | Date | |
|---|---|---|---|
| 22afdb20a4 | |||
| dca10507c0 | |||
| f8abae63b3 |
18 changed files with 2298 additions and 1439 deletions
1482
game/client.c
1482
game/client.c
File diff suppressed because it is too large
Load diff
1174
game/client.c.bak
Normal file
1174
game/client.c.bak
Normal file
File diff suppressed because it is too large
Load diff
218
game/client.sui
218
game/client.sui
|
|
@ -1,218 +0,0 @@
|
|||
Wildered
|
||||
wildered.da.programmer
|
||||
Online
|
||||
|
||||
Masashi
|
||||
|
||||
— 5:27 PM
|
||||
ill add both
|
||||
Wildered — 5:27 PM
|
||||
and allow for using variables obv
|
||||
duh
|
||||
ii love you
|
||||
not in the homo way
|
||||
xd
|
||||
Masashi
|
||||
|
||||
— 5:27 PM
|
||||
okok
|
||||
love u too bro (no homo)
|
||||
Wildered — 5:28 PM
|
||||
lol
|
||||
Masashi
|
||||
|
||||
— 5:32 PM
|
||||
fuck
|
||||
nishi's new version of libfishsoup
|
||||
broke our compiler
|
||||
:despair:
|
||||
bitwise added
|
||||
now arrays
|
||||
Masashi
|
||||
|
||||
— 5:39 PM
|
||||
@Wildered
|
||||
Wildered — 5:40 PM
|
||||
yes
|
||||
Masashi
|
||||
|
||||
— 5:40 PM
|
||||
because of the way our typesystem works
|
||||
we DONT have null
|
||||
ull need to do [Option::None; size]
|
||||
is that okay?
|
||||
and whatever ur using just make it Option::Some
|
||||
oh wait
|
||||
enums dont work
|
||||
................
|
||||
@Wildered what do we do
|
||||
wait we can do this
|
||||
say u want an array of type T
|
||||
u make struct TWrapper
|
||||
with val: T and is_used: bool
|
||||
how's the idea
|
||||
Wildered — 5:45 PM
|
||||
hi
|
||||
yes
|
||||
that's fine
|
||||
Wildered — 5:46 PM
|
||||
this is ok
|
||||
no worries
|
||||
Masashi
|
||||
|
||||
— 5:46 PM
|
||||
homemade Option 😭
|
||||
Wildered — 5:46 PM
|
||||
lmao\
|
||||
Masashi
|
||||
|
||||
— 5:46 PM
|
||||
doesnt work
|
||||
Masashi
|
||||
|
||||
— 5:46 PM
|
||||
.
|
||||
Wildered — 5:46 PM
|
||||
im fine w it
|
||||
what's the syntax for it
|
||||
Masashi
|
||||
|
||||
— 5:46 PM
|
||||
w
|
||||
fn main() -> int do
|
||||
let arr: [int; 5] = [42; 5];
|
||||
let x = arr[2];
|
||||
x
|
||||
end
|
||||
Wildered — 5:47 PM
|
||||
so 42 is the default
|
||||
Masashi
|
||||
|
||||
— 5:47 PM
|
||||
correct
|
||||
Wildered — 5:47 PM
|
||||
that's brilliant yay
|
||||
:D
|
||||
Masashi
|
||||
|
||||
— 5:48 PM
|
||||
:3
|
||||
Masashi
|
||||
|
||||
— 6:47 PM
|
||||
progress?
|
||||
Wildered — 6:55 PM
|
||||
almost done
|
||||
sneakpeak
|
||||
Image
|
||||
Starting import resolution...
|
||||
[parsing] game/client.sui
|
||||
Error: Parse error in game/client.sui: Unexpected token in pattern: KeywordElse. Expected variable names, struct patterns like Struct { field }, or enum patterns like Enum::Variant
|
||||
34 | else
|
||||
| ~~~~
|
||||
| ^
|
||||
fn main() -> int do
|
||||
suic_init_window(1280, 720, "Soup - Voxel Battle Royale");
|
||||
suic_enable_msaa_4x();
|
||||
let current_screen = 0;
|
||||
let player_name = "Player";
|
||||
let server_host = "127.0.0.1";
|
||||
Expand
|
||||
message.txt
|
||||
5 KB
|
||||
|
||||
fn main() -> int do
|
||||
suic_init_window(1280, 720, "Soup - Voxel Battle Royale");
|
||||
suic_enable_msaa_4x();
|
||||
let current_screen = 0;
|
||||
let player_name = "Player";
|
||||
let server_host = "127.0.0.1";
|
||||
let server_port = 8888;
|
||||
suic_show_fps_meter(suic_vec2 { x: 10.0, y: 10.0 });
|
||||
|
||||
while suic_window_should_close() == false do
|
||||
suic_begin_drawing();
|
||||
suic_clear_background(30, 30, 40, 255);
|
||||
|
||||
if current_screen == 0 do
|
||||
suic_draw_text("SOUP", 450, 80, 120, 100, 200, 255, 255);
|
||||
suic_draw_text("Voxel Battle Royale", 400, 220, 40, 200, 200, 200, 255);
|
||||
suic_draw_rectangle(450, 320, 380, 80, 50, 150, 255, 255);
|
||||
suic_draw_rectangle_lines(450, 320, 380, 80, 100, 200, 255, 255);
|
||||
suic_draw_text("PLAY", 600, 350, 40, 255, 255, 255, 255);
|
||||
suic_draw_rectangle(450, 430, 380, 80, 100, 100, 100, 255);
|
||||
suic_draw_rectangle_lines(450, 430, 380, 80, 150, 150, 150, 255);
|
||||
suic_draw_text("SETTINGS", 540, 460, 40, 255, 255, 255, 255);
|
||||
suic_draw_rectangle(450, 540, 380, 80, 150, 50, 50, 255);
|
||||
suic_draw_rectangle_lines(450, 540, 380, 80, 200, 100, 100, 255);
|
||||
suic_draw_text("QUIT", 600, 570, 40, 255, 255, 255, 255);
|
||||
suic_draw_text("v0.1.0 - Early Access", 500, 680, 20, 150, 150, 150, 255);
|
||||
|
||||
let mouse_x = suic_get_mouse_x() as int;
|
||||
let mouse_y = suic_get_mouse_y() as int;
|
||||
let is_mouse_clicked = suic_is_mouse_button_pressed(MOUSE_BUTTON_LEFT);
|
||||
|
||||
if mouse_x >= 450 && mouse_x <= 830 && mouse_y >= 320 && mouse_y <= 400 && is_mouse_clicked != 0 do
|
||||
current_screen = 1;
|
||||
end
|
||||
|
||||
if mouse_x >= 450 && mouse_x <= 830 && mouse_y >= 430 && mouse_y <= 510 && is_mouse_clicked != 0 do
|
||||
current_screen = 2;
|
||||
end
|
||||
|
||||
if mouse_x >= 450 && mouse_x <= 830 && mouse_y >= 540 && mouse_y <= 620 && is_mouse_clicked != 0 do
|
||||
break;
|
||||
end
|
||||
end
|
||||
if current_screen == 1 do
|
||||
suic_draw_text("MATCHMAKING", 450, 100, 60, 100, 200, 255, 255);
|
||||
suic_draw_text("Connecting to server...", 400, 250, 30, 200, 200, 200, 255);
|
||||
suic_draw_text("Host: 127.0.0.1:8888", 400, 310, 20, 150, 150, 150, 255);
|
||||
suic_draw_text("Your Name: Player", 400, 380, 20, 200, 200, 200, 255);
|
||||
suic_draw_text("Players in Queue: 0/100", 400, 420, 20, 200, 200, 200, 255);
|
||||
suic_draw_text("Loading...", 550, 500, 30, 100, 200, 255, 255);
|
||||
suic_draw_rectangle(100, 630, 150, 60, 150, 50, 50, 255);
|
||||
suic_draw_rectangle_lines(100, 630, 150, 60, 200, 100, 100, 255);
|
||||
suic_draw_text("BACK", 120, 650, 30, 255, 255, 255, 255);
|
||||
|
||||
let mouse_x = suic_get_mouse_x() as int;
|
||||
let mouse_y = suic_get_mouse_y() as int;
|
||||
let is_mouse_clicked = suic_is_mouse_button_pressed(MOUSE_BUTTON_LEFT);
|
||||
|
||||
if mouse_x >= 100 && mouse_x <= 250 && mouse_y >= 630 && mouse_y <= 690 && is_mouse_clicked != 0 do
|
||||
current_screen = 0;
|
||||
end
|
||||
end
|
||||
if current_screen == 2 do
|
||||
suic_draw_text("SETTINGS", 450, 100, 60, 100, 200, 255, 255);
|
||||
suic_draw_text("Player Name:", 250, 200, 24, 200, 200, 200, 255);
|
||||
suic_draw_rectangle(450, 190, 300, 50, 50, 50, 50, 255);
|
||||
suic_draw_rectangle_lines(450, 190, 300, 50, 100, 100, 100, 255);
|
||||
suic_draw_text("Player", 460, 205, 20, 255, 255, 255, 255);
|
||||
suic_draw_text("Server Host:", 250, 300, 24, 200, 200, 200, 255);
|
||||
suic_draw_rectangle(450, 290, 300, 50, 50, 50, 50, 255);
|
||||
suic_draw_rectangle_lines(450, 290, 300, 50, 100, 100, 100, 255);
|
||||
suic_draw_text("127.0.0.1", 460, 305, 20, 255, 255, 255, 255);
|
||||
suic_draw_text("Server Port:", 250, 400, 24, 200, 200, 200, 255);
|
||||
suic_draw_rectangle(450, 390, 300, 50, 50, 50, 50, 255);
|
||||
suic_draw_rectangle_lines(450, 390, 300, 50, 100, 100, 100, 255);
|
||||
suic_draw_text("8888", 460, 405, 20, 255, 255, 255, 255);
|
||||
suic_draw_rectangle(450, 550, 300, 70, 100, 100, 100, 255);
|
||||
suic_draw_rectangle_lines(450, 550, 300, 70, 150, 150, 150, 255);
|
||||
suic_draw_text("BACK TO HOME", 495, 577, 30, 255, 255, 255, 255);
|
||||
|
||||
let mouse_x = suic_get_mouse_x() as int;
|
||||
let mouse_y = suic_get_mouse_y() as int;
|
||||
let is_mouse_clicked = suic_is_mouse_button_pressed(MOUSE_BUTTON_LEFT);
|
||||
|
||||
if mouse_x >= 450 && mouse_x <= 750 && mouse_y >= 550 && mouse_y <= 620 && is_mouse_clicked != 0 do
|
||||
current_screen = 0;
|
||||
end
|
||||
end
|
||||
|
||||
suic_end_drawing();
|
||||
end
|
||||
|
||||
suic_close_window();
|
||||
0
|
||||
end
|
||||
23
src/ast.rs
23
src/ast.rs
|
|
@ -11,6 +11,7 @@ pub enum TypeAnnot {
|
|||
Function(Vec<TypeAnnot>, Box<TypeAnnot>),
|
||||
Tuple(Vec<TypeAnnot>),
|
||||
Array(Box<TypeAnnot>),
|
||||
FixedArray(Box<TypeAnnot>, i64),
|
||||
Ptr(Box<TypeAnnot>),
|
||||
}
|
||||
|
||||
|
|
@ -66,6 +67,7 @@ pub enum ASTNodeKind {
|
|||
Function(Function),
|
||||
Extern(Extern),
|
||||
Load(Load),
|
||||
Const(Const),
|
||||
Struct(Struct),
|
||||
Enum(Enum),
|
||||
Impl(Impl),
|
||||
|
|
@ -79,6 +81,13 @@ pub struct Use {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Const {
|
||||
pub name: String,
|
||||
pub typ: Option<TypeAnnot>,
|
||||
pub value: Expr,
|
||||
}
|
||||
|
||||
// ? implies OPTIONAL here
|
||||
// \( implies the presence of (. same for /)
|
||||
|
||||
|
|
@ -204,10 +213,12 @@ pub struct Expr {
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum ExprKind {
|
||||
Int(i64),
|
||||
TypedInt(i64, String),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
String(String),
|
||||
Array(Vec<Expr>),
|
||||
FixedArray(Box<Expr>, i64),
|
||||
Tuple(Vec<Expr>),
|
||||
|
||||
StructLit(String, Vec<(String, Expr)>), // Name { a: expr, b: expr }
|
||||
|
|
@ -262,6 +273,8 @@ pub enum BinOp {
|
|||
Or,
|
||||
BitwiseAnd,
|
||||
BitwiseOr,
|
||||
LShift,
|
||||
RShift,
|
||||
Eq,
|
||||
Neq,
|
||||
Lt,
|
||||
|
|
@ -311,6 +324,7 @@ pub enum TypedASTNodeKind {
|
|||
Function(TypedFunction),
|
||||
Extern(TypedExtern),
|
||||
Load(TypedLoad),
|
||||
Const(TypedConst),
|
||||
Struct(TypedStruct),
|
||||
Enum(TypedEnum),
|
||||
Impl(TypedImpl),
|
||||
|
|
@ -344,6 +358,13 @@ pub struct TypedLoad {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TypedConst {
|
||||
pub name: String,
|
||||
pub typ: Option<TypeAnnot>,
|
||||
pub value: TypedExpr,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TypedStruct {
|
||||
pub name: String,
|
||||
|
|
@ -398,10 +419,12 @@ pub struct TypedExpr {
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum TypedExprKind {
|
||||
Int(i64),
|
||||
TypedInt(i64, String),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
String(String),
|
||||
Array(Vec<TypedExpr>),
|
||||
FixedArray(Box<TypedExpr>, usize),
|
||||
Tuple(Vec<TypedExpr>),
|
||||
StructLit(String, Vec<(String, TypedExpr)>),
|
||||
EnumLit(String, String, Vec<TypedExpr>),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
pub enum CType {
|
||||
Void,
|
||||
Int,
|
||||
U8,
|
||||
Float,
|
||||
Bool,
|
||||
Char,
|
||||
|
|
@ -9,6 +10,7 @@ pub enum CType {
|
|||
Struct(String),
|
||||
UnnamedStruct(Vec<CVarDecl>),
|
||||
Array(Box<CType>), // heap-allocated array wrapper with data pointer, len, capacity
|
||||
FixedArray(Box<CType>, usize), // fixed-size array like int[10]
|
||||
Func(Vec<CType>, Box<CType>), // args and return
|
||||
}
|
||||
|
||||
|
|
@ -32,6 +34,7 @@ impl CType {
|
|||
match self {
|
||||
CType::Void => "void".to_string(),
|
||||
CType::Int => "int".to_string(),
|
||||
CType::U8 => "uint8_t".to_string(),
|
||||
CType::Float => "float".to_string(),
|
||||
CType::Bool => "bool".to_string(),
|
||||
CType::Char => "char".to_string(),
|
||||
|
|
@ -48,6 +51,7 @@ impl CType {
|
|||
"struct sui_array_{}",
|
||||
inner.to_string().replace(" ", "_").replace("*", "ptr")
|
||||
),
|
||||
CType::FixedArray(inner, size) => format!("{}*", inner.to_string()), // For now, treat as pointer in type strings
|
||||
CType::Func(args, ret) => {
|
||||
let arg_strs: Vec<String> = args.iter().map(|t| t.to_string()).collect();
|
||||
format!("{} (*)({})", ret.to_string(), arg_strs.join(", "))
|
||||
|
|
@ -61,6 +65,7 @@ pub struct CVarDecl {
|
|||
pub name: String,
|
||||
pub ty: CType,
|
||||
pub initializer: Option<CExpr>,
|
||||
pub is_const: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
|
@ -116,6 +121,8 @@ pub enum CBinaryOp {
|
|||
Or,
|
||||
BitwiseAnd,
|
||||
BitwiseOr,
|
||||
LShift,
|
||||
RShift,
|
||||
}
|
||||
|
||||
impl CBinaryOp {
|
||||
|
|
@ -136,6 +143,8 @@ impl CBinaryOp {
|
|||
CBinaryOp::Or => "||",
|
||||
CBinaryOp::BitwiseAnd => "&",
|
||||
CBinaryOp::BitwiseOr => "|",
|
||||
CBinaryOp::LShift => "<<",
|
||||
CBinaryOp::RShift => ">>",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ impl DeclarationTranspiler {
|
|||
name: field.name.clone(),
|
||||
ty: field_type,
|
||||
initializer: None,
|
||||
is_const: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +54,7 @@ impl DeclarationTranspiler {
|
|||
name: name.clone(),
|
||||
ty: param_type,
|
||||
initializer: None,
|
||||
is_const: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +83,7 @@ impl DeclarationTranspiler {
|
|||
name: field_name,
|
||||
ty: c_type,
|
||||
initializer: None,
|
||||
is_const: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -100,6 +103,7 @@ impl DeclarationTranspiler {
|
|||
name: field_name,
|
||||
ty: CType::Struct(struct_name),
|
||||
initializer: None,
|
||||
is_const: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -115,11 +119,13 @@ impl DeclarationTranspiler {
|
|||
name: "discriminant".to_string(),
|
||||
ty: CType::Int,
|
||||
initializer: None,
|
||||
is_const: false,
|
||||
},
|
||||
CVarDecl {
|
||||
name: "data".to_string(),
|
||||
ty: CType::Struct(union_name_clone),
|
||||
initializer: None,
|
||||
is_const: false,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -148,6 +154,10 @@ impl DeclarationTranspiler {
|
|||
// Arrays are pointers to the element type
|
||||
Ok(CType::Ptr(Box::new(inner_type)))
|
||||
}
|
||||
Some(TypeAnnot::FixedArray(inner, size)) => {
|
||||
let inner_type = self.type_annot_to_c_type(&Some(*inner.clone()))?;
|
||||
Ok(CType::FixedArray(Box::new(inner_type), *size as usize))
|
||||
}
|
||||
Some(TypeAnnot::Tuple(fields)) => {
|
||||
let mut c_fields = Vec::new();
|
||||
for (i, field_annot) in fields.iter().enumerate() {
|
||||
|
|
@ -156,6 +166,7 @@ impl DeclarationTranspiler {
|
|||
name: format!("field{}", i),
|
||||
ty: field_type,
|
||||
initializer: None,
|
||||
is_const: false,
|
||||
});
|
||||
}
|
||||
Ok(CType::UnnamedStruct(c_fields))
|
||||
|
|
@ -176,6 +187,7 @@ impl DeclarationTranspiler {
|
|||
pub fn convert_to_c_type(name: &String) -> Result<CType, String> {
|
||||
match String::as_str(name) {
|
||||
"int" => Ok(CType::Int),
|
||||
"u8" => Ok(CType::U8),
|
||||
"float" => Ok(CType::Float),
|
||||
"bool" => Ok(CType::Bool),
|
||||
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ impl StatementsTranspiler {
|
|||
name: name.clone(),
|
||||
ty,
|
||||
initializer,
|
||||
is_const: false,
|
||||
};
|
||||
|
||||
(name, decl)
|
||||
|
|
@ -48,6 +49,13 @@ impl StatementsTranspiler {
|
|||
pub fn transpile_expr(&self, expr: &TypedExpr) -> Result<CExpr, String> {
|
||||
match &expr.kind {
|
||||
TypedExprKind::Int(i) => Ok(CExpr::IntLit(*i)),
|
||||
TypedExprKind::TypedInt(i, t) => {
|
||||
let inner = CExpr::IntLit(*i);
|
||||
match t.as_str() {
|
||||
"u8" => Ok(CExpr::Cast(Box::new(inner), CType::U8)),
|
||||
_ => Err(format!("Unsupported typed integer type: {}", t)),
|
||||
}
|
||||
}
|
||||
TypedExprKind::Float(f) => Ok(CExpr::FloatLit(*f)),
|
||||
TypedExprKind::Bool(b) => Ok(CExpr::BoolLit(*b)),
|
||||
TypedExprKind::String(s) => Ok(CExpr::StringLit(s.clone())),
|
||||
|
|
@ -117,6 +125,11 @@ impl StatementsTranspiler {
|
|||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(CExpr::ArrayLit(c_exprs))
|
||||
}
|
||||
TypedExprKind::FixedArray(expr, size) => {
|
||||
let c_expr = self.transpile_expr(expr)?;
|
||||
let c_exprs = vec![c_expr; *size];
|
||||
Ok(CExpr::ArrayLit(c_exprs))
|
||||
}
|
||||
TypedExprKind::Cast(expr, type_annot) => {
|
||||
let c_expr = self.transpile_expr(expr)?;
|
||||
// Simplified: assuming we can map type annotations to C types
|
||||
|
|
@ -170,6 +183,7 @@ impl StatementsTranspiler {
|
|||
name: name.clone(),
|
||||
ty: c_type,
|
||||
initializer,
|
||||
is_const: false,
|
||||
};
|
||||
Ok(CStmt::VarDecl(var_decl))
|
||||
}
|
||||
|
|
@ -221,6 +235,7 @@ impl StatementsTranspiler {
|
|||
name: var_name.clone(),
|
||||
ty: CType::Int,
|
||||
initializer: Some(start_expr),
|
||||
is_const: false,
|
||||
};
|
||||
|
||||
let cond = CExpr::BinOp(
|
||||
|
|
@ -272,6 +287,7 @@ impl StatementsTranspiler {
|
|||
)),
|
||||
Box::new(CExpr::Var(idx_name.clone())),
|
||||
)),
|
||||
is_const: false,
|
||||
});
|
||||
|
||||
let mut body_stmts = vec![bind];
|
||||
|
|
@ -321,6 +337,7 @@ impl StatementsTranspiler {
|
|||
Box::new(CExpr::Var(arr_name.clone())),
|
||||
Box::new(CExpr::Var(idx_name.clone())),
|
||||
)),
|
||||
is_const: false,
|
||||
});
|
||||
|
||||
let mut body_stmts = vec![bind];
|
||||
|
|
@ -456,6 +473,8 @@ impl StatementsTranspiler {
|
|||
BinOp::Or => Ok(CBinaryOp::Or),
|
||||
BinOp::BitwiseAnd => Ok(CBinaryOp::BitwiseAnd),
|
||||
BinOp::BitwiseOr => Ok(CBinaryOp::BitwiseOr),
|
||||
BinOp::LShift => Ok(CBinaryOp::LShift),
|
||||
BinOp::RShift => Ok(CBinaryOp::RShift),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -469,9 +488,10 @@ impl StatementsTranspiler {
|
|||
}
|
||||
}
|
||||
|
||||
fn type_to_ctype(&self, ty: &Type) -> Result<CType, String> {
|
||||
pub fn type_to_ctype(&self, ty: &Type) -> Result<CType, String> {
|
||||
match ty {
|
||||
Type::Int => Ok(CType::Int),
|
||||
Type::U8 => Ok(CType::U8),
|
||||
Type::Float => Ok(CType::Float),
|
||||
Type::Bool => Ok(CType::Bool),
|
||||
Type::String => Ok(CType::Ptr(Box::new(CType::Char))),
|
||||
|
|
@ -482,6 +502,10 @@ impl StatementsTranspiler {
|
|||
// Arrays are pointers to the element type
|
||||
Ok(CType::Ptr(Box::new(inner_type)))
|
||||
}
|
||||
Type::FixedArray(inner, size) => {
|
||||
let inner_type = self.type_to_ctype(inner)?;
|
||||
Ok(CType::FixedArray(Box::new(inner_type), *size))
|
||||
}
|
||||
Type::Struct(name, _) => Ok(CType::Ptr(Box::new(CType::Struct(name.clone())))),
|
||||
Type::Enum(name, _) => Ok(CType::Ptr(Box::new(CType::Struct(name.clone())))),
|
||||
Type::Tuple(types) => {
|
||||
|
|
@ -492,6 +516,7 @@ impl StatementsTranspiler {
|
|||
name: format!("field{}", i),
|
||||
ty: c_type,
|
||||
initializer: None,
|
||||
is_const: false,
|
||||
});
|
||||
}
|
||||
Ok(CType::UnnamedStruct(fields))
|
||||
|
|
@ -536,6 +561,10 @@ impl StatementsTranspiler {
|
|||
// Arrays are pointers to the element type
|
||||
Ok(CType::Ptr(Box::new(inner_type)))
|
||||
}
|
||||
TypeAnnot::FixedArray(inner, size) => {
|
||||
let inner_type = self.type_annot_to_ctype(inner)?;
|
||||
Ok(CType::FixedArray(Box::new(inner_type), *size as usize))
|
||||
}
|
||||
TypeAnnot::Tuple(fields) => {
|
||||
let mut c_fields = Vec::new();
|
||||
for (i, field_annot) in fields.iter().enumerate() {
|
||||
|
|
@ -544,6 +573,7 @@ impl StatementsTranspiler {
|
|||
name: format!("field{}", i),
|
||||
ty: field_type,
|
||||
initializer: None,
|
||||
is_const: false,
|
||||
});
|
||||
}
|
||||
Ok(CType::UnnamedStruct(c_fields))
|
||||
|
|
|
|||
|
|
@ -90,6 +90,39 @@ impl Transpiler {
|
|||
self.lower_declarations_to_c_ir(node)?;
|
||||
}
|
||||
|
||||
// Add builtin structs
|
||||
if !self.structs.iter().any(|s| s.name == "Color") {
|
||||
self.structs.push(CStructDecl {
|
||||
name: "Color".to_string(),
|
||||
fields: vec![
|
||||
CVarDecl { name: "r".to_string(), ty: CType::U8, initializer: None, is_const: false },
|
||||
CVarDecl { name: "g".to_string(), ty: CType::U8, initializer: None, is_const: false },
|
||||
CVarDecl { name: "b".to_string(), ty: CType::U8, initializer: None, is_const: false },
|
||||
CVarDecl { name: "a".to_string(), ty: CType::U8, initializer: None, is_const: false },
|
||||
],
|
||||
});
|
||||
// Generate TypeInfo
|
||||
let bitmap = Self::generate_pointer_bitmap(&vec![
|
||||
CVarDecl { name: "r".to_string(), ty: CType::U8, initializer: None, is_const: false },
|
||||
CVarDecl { name: "g".to_string(), ty: CType::U8, initializer: None, is_const: false },
|
||||
CVarDecl { name: "b".to_string(), ty: CType::U8, initializer: None, is_const: false },
|
||||
CVarDecl { name: "a".to_string(), ty: CType::U8, initializer: None, is_const: false },
|
||||
]);
|
||||
self.typeinfo_map.insert("Color".to_string(), bitmap);
|
||||
}
|
||||
if !self.structs.iter().any(|s| s.name == "Shader") {
|
||||
self.structs.push(CStructDecl {
|
||||
name: "Shader".to_string(),
|
||||
fields: vec![
|
||||
CVarDecl { name: "id".to_string(), ty: CType::Int, initializer: None, is_const: false },
|
||||
],
|
||||
});
|
||||
let bitmap = Self::generate_pointer_bitmap(&vec![
|
||||
CVarDecl { name: "id".to_string(), ty: CType::Int, initializer: None, is_const: false },
|
||||
]);
|
||||
self.typeinfo_map.insert("Shader".to_string(), bitmap);
|
||||
}
|
||||
|
||||
self.lower_function_bodies_to_c_ir(nodes)?;
|
||||
|
||||
// Rename main to suic_main and track that we have a main
|
||||
|
|
@ -238,6 +271,16 @@ impl Transpiler {
|
|||
self.functions.push(func_decl);
|
||||
}
|
||||
}
|
||||
TypedASTNodeKind::Const(c) => {
|
||||
let value_code = self.stmt_transpiler.transpile_expr(&c.value)?;
|
||||
let var_decl = CVarDecl {
|
||||
name: c.name.clone(),
|
||||
ty: self.stmt_transpiler.type_to_ctype(&c.value.ty)?,
|
||||
initializer: Some(value_code),
|
||||
is_const: true,
|
||||
};
|
||||
self.globals.push(var_decl);
|
||||
}
|
||||
TypedASTNodeKind::Extern(e) => {
|
||||
// For externs, we might need to add function prototypes
|
||||
// But for now, skip as they're handled differently
|
||||
|
|
@ -404,9 +447,26 @@ impl Transpiler {
|
|||
}
|
||||
|
||||
fn generate_var_decl(&self, var: &CVarDecl) -> String {
|
||||
let mut output = format!("{} {}", var.ty.to_string(), var.name);
|
||||
let mut output = match &var.ty {
|
||||
CType::FixedArray(elem_ty, size) => format!("{} {}[{}]", elem_ty.to_string(), var.name, size),
|
||||
_ => format!("{} {}", var.ty.to_string(), var.name),
|
||||
};
|
||||
if var.is_const {
|
||||
output = format!("const {}", output);
|
||||
}
|
||||
if let Some(init) = &var.initializer {
|
||||
output.push_str(&format!(" = {}", self.generate_expr(init)));
|
||||
match (&var.ty, init) {
|
||||
(CType::FixedArray(_, _), CExpr::ArrayLit(elements)) => {
|
||||
let vec: Vec<String> = elements
|
||||
.iter()
|
||||
.map(|expr| self.generate_expr(expr))
|
||||
.collect();
|
||||
output.push_str(&format!(" = {{{}}}", vec.join(", ")));
|
||||
}
|
||||
_ => {
|
||||
output.push_str(&format!(" = {}", self.generate_expr(init)));
|
||||
}
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
|
@ -638,13 +698,14 @@ impl Transpiler {
|
|||
"rl_pop_matrix" => "suic_rl_pop_matrix",
|
||||
"rl_translate_f" => "suic_rl_translate_f",
|
||||
"rl_rotate_f" => "suic_rl_rotate_f",
|
||||
// UI Framework Utils
|
||||
"draw_text" => "suic_draw_text",
|
||||
"draw_rectangle" => "suic_draw_rectangle",
|
||||
"draw_rectangle_lines" => "suic_draw_rectangle_lines",
|
||||
"measure_text" => "suic_measure_text",
|
||||
"draw_circle" => "suic_draw_circle",
|
||||
"draw_line" => "suic_draw_line",
|
||||
// UI Framework Utils
|
||||
"draw_text" => "DrawText",
|
||||
"draw_rectangle" => "DrawRectangle",
|
||||
"draw_rectangle_lines" => "DrawRectangleLines",
|
||||
"measure_text" => "MeasureText",
|
||||
"draw_circle" => "DrawCircle",
|
||||
"draw_line" => "DrawLine",
|
||||
"draw_fps" => "DrawFPS",
|
||||
// Player controller functions
|
||||
"player_controller_create" => "suic_player_controller_create",
|
||||
"player_controller_destroy" => "suic_player_controller_destroy",
|
||||
|
|
@ -735,18 +796,7 @@ impl Transpiler {
|
|||
"Vec3" => "suic_vec3".to_string(),
|
||||
_ => format!("struct {}", struct_name),
|
||||
};
|
||||
// For built-in simple structs, generate compound literal directly
|
||||
// For user-defined structs, use heap allocation
|
||||
match struct_name.as_str() {
|
||||
"Vec2" | "Vec3" => format!("({}){{ {} }}", c_type_name, field_inits.join(", ")),
|
||||
_ => format!(
|
||||
"suic_alloc_struct(&sui_typeinfo_{}, sizeof({}), &({}){{ {} }})",
|
||||
struct_name,
|
||||
c_type_name,
|
||||
c_type_name,
|
||||
field_inits.join(", ")
|
||||
),
|
||||
}
|
||||
format!("({}){{ {} }}", c_type_name, field_inits.join(", "))
|
||||
}
|
||||
CExpr::EnumLit(enum_name, variant_name, args) => {
|
||||
// Find the variant index - for simplicity, assume variants are in order
|
||||
|
|
|
|||
|
|
@ -370,14 +370,22 @@ impl ImportResolver {
|
|||
ASTNodeKind::Load(_) => {
|
||||
result.push(node);
|
||||
}
|
||||
ASTNodeKind::Trait(t) => {
|
||||
self.symbol_registry.register(
|
||||
t.name.clone(),
|
||||
filename.to_string(),
|
||||
node.span.clone(),
|
||||
)?;
|
||||
result.push(node);
|
||||
}
|
||||
ASTNodeKind::Trait(t) => {
|
||||
self.symbol_registry.register(
|
||||
t.name.clone(),
|
||||
filename.to_string(),
|
||||
node.span.clone(),
|
||||
)?;
|
||||
result.push(node);
|
||||
}
|
||||
ASTNodeKind::Const(c) => {
|
||||
self.symbol_registry.register(
|
||||
c.name.clone(),
|
||||
filename.to_string(),
|
||||
node.span.clone(),
|
||||
)?;
|
||||
result.push(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,9 @@ impl LambdaLowerer {
|
|||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
||||
}
|
||||
}
|
||||
ExprKind::FixedArray(expr, _) => {
|
||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
||||
}
|
||||
ExprKind::Tuple(exprs) => {
|
||||
for expr in exprs {
|
||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
||||
|
|
@ -150,6 +153,7 @@ impl LambdaLowerer {
|
|||
}
|
||||
// Terminal expressions don't contain variables
|
||||
ExprKind::Int(_)
|
||||
| ExprKind::TypedInt(_, _)
|
||||
| ExprKind::Float(_)
|
||||
| ExprKind::Bool(_)
|
||||
| ExprKind::String(_)
|
||||
|
|
@ -340,6 +344,10 @@ impl LambdaLowerer {
|
|||
.collect::<Result<Vec<_>, _>>()?;
|
||||
ExprKind::Array(lowered_exprs)
|
||||
}
|
||||
ExprKind::FixedArray(expr, size) => {
|
||||
let lowered_expr = self.lower_expr(expr)?;
|
||||
ExprKind::FixedArray(Box::new(lowered_expr), *size)
|
||||
}
|
||||
ExprKind::Tuple(exprs) => {
|
||||
let lowered_exprs = exprs
|
||||
.iter()
|
||||
|
|
@ -369,6 +377,7 @@ impl LambdaLowerer {
|
|||
}
|
||||
// Terminal expressions that don't contain other expressions
|
||||
ExprKind::Int(_)
|
||||
| ExprKind::TypedInt(_, _)
|
||||
| ExprKind::Float(_)
|
||||
| ExprKind::Bool(_)
|
||||
| ExprKind::String(_)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,14 @@ pub enum Token {
|
|||
}, priority = 4)]
|
||||
Int(i64),
|
||||
|
||||
#[regex(r"(0|[1-9][0-9_]*)u8", |lex| {
|
||||
let s = lex.slice();
|
||||
let num_part = &s[..s.len()-2];
|
||||
let num = num_part.replace("_", "").parse::<i64>().unwrap();
|
||||
(num, "u8".to_string())
|
||||
}, priority = 5)]
|
||||
TypedInt((i64, String)),
|
||||
|
||||
#[regex(r"(([0-9][0-9_]*\.[0-9_]+|[0-9]*\.[0-9_]+)([eE][+-]?[0-9_]+)?)", |lex| {
|
||||
let s = lex.slice().replace("_", "");
|
||||
s.parse::<f64>().unwrap()
|
||||
|
|
@ -61,6 +69,9 @@ pub enum Token {
|
|||
#[token("string")]
|
||||
KeywordString,
|
||||
|
||||
#[token("u8")]
|
||||
KeywordU8,
|
||||
|
||||
#[token("let")]
|
||||
KeywordLet,
|
||||
|
||||
|
|
@ -135,6 +146,9 @@ pub enum Token {
|
|||
#[token("trait")]
|
||||
KeywordTrait,
|
||||
|
||||
#[token("const")]
|
||||
KeywordConst,
|
||||
|
||||
// #[token("type")]
|
||||
// KeywordType,
|
||||
//
|
||||
|
|
@ -171,6 +185,12 @@ pub enum Token {
|
|||
#[token("**", priority = 3)]
|
||||
Power,
|
||||
|
||||
#[token("<<")]
|
||||
LShift,
|
||||
|
||||
#[token(">>")]
|
||||
RShift,
|
||||
|
||||
#[token("$")]
|
||||
Dollar,
|
||||
|
||||
|
|
|
|||
|
|
@ -244,6 +244,9 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> {
|
|||
suicmez::ast::TypedASTNodeKind::Function(f) => {
|
||||
format!("Function({})", f.name)
|
||||
}
|
||||
suicmez::ast::TypedASTNodeKind::Const(c) => {
|
||||
format!("Const({})", c.name)
|
||||
}
|
||||
suicmez::ast::TypedASTNodeKind::Struct(s) => {
|
||||
format!("Struct({}) with {} params", s.name, s.parameters.len())
|
||||
}
|
||||
|
|
@ -297,6 +300,9 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> {
|
|||
suicmez::ast::TypedASTNodeKind::Function(f) => {
|
||||
format!("Function({})", f.name)
|
||||
}
|
||||
suicmez::ast::TypedASTNodeKind::Const(c) => {
|
||||
format!("Const({})", c.name)
|
||||
}
|
||||
suicmez::ast::TypedASTNodeKind::Struct(s) => {
|
||||
format!("Struct({}) with {} params", s.name, s.parameters.len())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ impl Monomorphizer {
|
|||
|
||||
for (_idx, node) in nodes.iter().enumerate() {
|
||||
match &node.kind {
|
||||
TypedASTNodeKind::Const(c) => {
|
||||
result_nodes.push(node.clone());
|
||||
}
|
||||
TypedASTNodeKind::Function(f) => {
|
||||
// Skip generic functions - they'll be added as specialized versions when needed
|
||||
if !f.parameters.is_empty() {
|
||||
|
|
@ -322,6 +325,7 @@ impl Monomorphizer {
|
|||
let mut needs = Vec::new();
|
||||
let new_kind = match &expr.kind {
|
||||
TypedExprKind::Int(_)
|
||||
| TypedExprKind::TypedInt(_, _)
|
||||
| TypedExprKind::Float(_)
|
||||
| TypedExprKind::Bool(_)
|
||||
| TypedExprKind::String(_)
|
||||
|
|
@ -342,6 +346,11 @@ impl Monomorphizer {
|
|||
}
|
||||
TypedExprKind::Array(new_elems)
|
||||
}
|
||||
TypedExprKind::FixedArray(expr, size) => {
|
||||
let (new_expr, expr_needs) = self.monomorphize_expr(expr)?;
|
||||
needs.extend(expr_needs);
|
||||
TypedExprKind::FixedArray(Box::new(new_expr), *size)
|
||||
}
|
||||
|
||||
TypedExprKind::Tuple(elems) => {
|
||||
let mut new_elems = Vec::new();
|
||||
|
|
@ -767,6 +776,10 @@ impl Monomorphizer {
|
|||
let new_inner = self.substitute_in_type_annot(inner, subst_map)?;
|
||||
Ok(TypeAnnot::Array(Box::new(new_inner)))
|
||||
}
|
||||
TypeAnnot::FixedArray(inner, size) => {
|
||||
let new_inner = self.substitute_in_type_annot(inner, subst_map)?;
|
||||
Ok(TypeAnnot::FixedArray(Box::new(new_inner), *size))
|
||||
}
|
||||
TypeAnnot::Ptr(inner) => {
|
||||
let new_inner = self.substitute_in_type_annot(inner, subst_map)?;
|
||||
Ok(TypeAnnot::Ptr(Box::new(new_inner)))
|
||||
|
|
@ -777,11 +790,13 @@ impl Monomorphizer {
|
|||
fn type_to_type_annot(&self, ty: &Type) -> TypeAnnot {
|
||||
match ty {
|
||||
Type::Int => TypeAnnot::Var("int".to_string()),
|
||||
Type::U8 => TypeAnnot::Var("u8".to_string()),
|
||||
Type::Float => TypeAnnot::Var("float".to_string()),
|
||||
Type::Bool => TypeAnnot::Var("bool".to_string()),
|
||||
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::FixedArray(inner, size) => TypeAnnot::FixedArray(Box::new(self.type_to_type_annot(inner)), *size as i64),
|
||||
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();
|
||||
|
|
@ -901,6 +916,9 @@ impl Monomorphizer {
|
|||
TypeAnnot::Array(inner) => {
|
||||
self.collect_needs_from_type(inner, needs);
|
||||
}
|
||||
TypeAnnot::FixedArray(inner, _) => {
|
||||
self.collect_needs_from_type(inner, needs);
|
||||
}
|
||||
TypeAnnot::Ptr(inner) => {
|
||||
self.collect_needs_from_type(inner, needs);
|
||||
}
|
||||
|
|
@ -932,10 +950,8 @@ impl Monomorphizer {
|
|||
let tys = types.iter().map(|t| self.type_annot_to_type(t)).collect();
|
||||
Type::Tuple(tys)
|
||||
}
|
||||
TypeAnnot::Array(inner) => {
|
||||
let inner_type = self.type_annot_to_type(inner);
|
||||
Type::Array(Box::new(inner_type))
|
||||
}
|
||||
TypeAnnot::Array(inner) => Type::Array(Box::new(self.type_annot_to_type(inner))),
|
||||
TypeAnnot::FixedArray(inner, size) => Type::FixedArray(Box::new(self.type_annot_to_type(inner)), *size as usize),
|
||||
TypeAnnot::Ptr(inner) => {
|
||||
let inner_type = self.type_annot_to_type(inner);
|
||||
Type::Ptr(Box::new(inner_type))
|
||||
|
|
@ -975,6 +991,9 @@ fn check_node_for_typevars(node: &TypedASTNode) -> Result<(), MonomorphizationEr
|
|||
TypedASTNodeKind::Function(f) => {
|
||||
check_function_for_typevars(f)?;
|
||||
}
|
||||
TypedASTNodeKind::Const(c) => {
|
||||
// Consts should not have typevars
|
||||
}
|
||||
TypedASTNodeKind::Struct(s) => {
|
||||
check_struct_for_typevars(s)?;
|
||||
}
|
||||
|
|
@ -1216,6 +1235,7 @@ 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::FixedArray(inner, _) => has_typevars_in_type_annot(inner),
|
||||
TypeAnnot::Ptr(inner) => has_typevars_in_type_annot(inner),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
149
src/parser.rs
149
src/parser.rs
|
|
@ -149,6 +149,16 @@ impl Parser {
|
|||
attributes,
|
||||
})
|
||||
}
|
||||
Some(Token::KeywordConst) => {
|
||||
self.next();
|
||||
let const_def = self.parse_const()?;
|
||||
let end = self.peek_span().unwrap_or(start..start).end;
|
||||
Ok(ASTNode {
|
||||
kind: ASTNodeKind::Const(const_def),
|
||||
span: Span::new(&(start..end), self.file.clone()),
|
||||
attributes,
|
||||
})
|
||||
}
|
||||
Some(Token::KeywordStruct) => {
|
||||
self.next();
|
||||
let struct_def = self.parse_struct()?;
|
||||
|
|
@ -211,12 +221,33 @@ impl Parser {
|
|||
}
|
||||
Some(token) => {
|
||||
let span = self.peek_span().unwrap_or(start..start);
|
||||
self.error(format!("Unexpected token at top level: {:?}. Expected declarations like 'fn', 'struct', 'enum', 'impl', 'trait', 'use', 'load', or 'extern'", token), span)
|
||||
self.error(format!("Unexpected token at top level: {:?}. Expected declarations like 'fn', 'struct', 'enum', 'impl', 'trait', 'const', 'use', 'load', or 'extern'", token), span)
|
||||
}
|
||||
None => self.error("Unexpected end of file at top level. Expected declarations like 'fn', 'struct', 'enum', etc.".to_string(), start..start),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_const(&mut self) -> Result<Const, ParseError> {
|
||||
let start = self.peek_span().unwrap_or(0..0).start;
|
||||
let name = match self.next() {
|
||||
Some((Token::Variable(n), _)) => n,
|
||||
Some((_, span)) => return self.error("Expected constant name after 'const' keyword. Example: const PI = 3.14".to_string(), span),
|
||||
None => return self.error("Expected constant name after 'const' keyword. Example: const PI = 3.14".to_string(), start..start),
|
||||
};
|
||||
|
||||
let typ = if matches!(self.peek(), Some(Token::Colon)) {
|
||||
self.next();
|
||||
Some(self.parse_type_annot()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.expect(Token::Assign)?;
|
||||
let value = self.parse_expr()?;
|
||||
|
||||
Ok(Const { name, typ, value })
|
||||
}
|
||||
|
||||
fn parse_attribute(&mut self) -> Result<Attribute, ParseError> {
|
||||
self.expect(Token::At)?;
|
||||
let start = self.peek_span().unwrap_or(0..0).start;
|
||||
|
|
@ -883,6 +914,7 @@ impl Parser {
|
|||
Some((Token::KeywordInt, _)) => TypeAnnot::Cons("int".to_string(), vec![]),
|
||||
Some((Token::KeywordFloat, _)) => TypeAnnot::Cons("float".to_string(), vec![]),
|
||||
Some((Token::KeywordString, _)) => TypeAnnot::Cons("string".to_string(), vec![]),
|
||||
Some((Token::KeywordU8, _)) => TypeAnnot::Cons("u8".to_string(), vec![]),
|
||||
Some((Token::LParen, _)) => {
|
||||
// Check for unit type: ()
|
||||
if matches!(self.peek(), Some(Token::RParen)) {
|
||||
|
|
@ -912,8 +944,23 @@ impl Parser {
|
|||
}
|
||||
Some((Token::LBracket, _)) => {
|
||||
let inner = self.parse_type_annot()?;
|
||||
self.expect(Token::RBracket)?;
|
||||
TypeAnnot::Array(Box::new(inner))
|
||||
if matches!(self.peek(), Some(Token::Semicolon)) {
|
||||
self.next();
|
||||
let size = match self.next() {
|
||||
Some((Token::Int(n), _)) => n,
|
||||
Some((_, span)) => {
|
||||
return self.error("Expected integer size for fixed array".to_string(), span);
|
||||
}
|
||||
None => {
|
||||
return self.error("Expected integer size for fixed array".to_string(), start..start);
|
||||
}
|
||||
};
|
||||
self.expect(Token::RBracket)?;
|
||||
TypeAnnot::FixedArray(Box::new(inner), size)
|
||||
} else {
|
||||
self.expect(Token::RBracket)?;
|
||||
TypeAnnot::Array(Box::new(inner))
|
||||
}
|
||||
}
|
||||
Some((Token::Bang, _)) => TypeAnnot::Cons("never".to_string(), vec![]),
|
||||
Some((_, span)) => {
|
||||
|
|
@ -1157,14 +1204,44 @@ impl Parser {
|
|||
Ok(left)
|
||||
}
|
||||
|
||||
fn parse_bitwise_and_expr(&mut self) -> Result<Expr, ParseError> {
|
||||
fn parse_shift_expr(&mut self) -> Result<Expr, ParseError> {
|
||||
let mut left = self.parse_eq_expr()?;
|
||||
|
||||
loop {
|
||||
let op = if matches!(self.peek(), Some(Token::LShift)) {
|
||||
Some(BinOp::LShift)
|
||||
} else if matches!(self.peek(), Some(Token::RShift)) {
|
||||
Some(BinOp::RShift)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(op) = op {
|
||||
let start = left.span.start;
|
||||
self.next();
|
||||
let right = self.parse_eq_expr()?;
|
||||
let end = right.span.end;
|
||||
left = Expr {
|
||||
kind: ExprKind::BinOp(Box::new(left), op, Box::new(right)),
|
||||
span: Span::new(&(start..end), self.file.clone()),
|
||||
attributes: Vec::new(),
|
||||
};
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(left)
|
||||
}
|
||||
|
||||
fn parse_bitwise_and_expr(&mut self) -> Result<Expr, ParseError> {
|
||||
let mut left = self.parse_shift_expr()?;
|
||||
|
||||
loop {
|
||||
if matches!(self.peek(), Some(Token::BitAnd)) {
|
||||
let start = left.span.start;
|
||||
self.next();
|
||||
let right = self.parse_eq_expr()?;
|
||||
let right = self.parse_shift_expr()?;
|
||||
let end = right.span.end;
|
||||
left = Expr {
|
||||
kind: ExprKind::BinOp(Box::new(left), BinOp::BitwiseAnd, Box::new(right)),
|
||||
|
|
@ -1450,6 +1527,15 @@ impl Parser {
|
|||
attributes: Vec::new(),
|
||||
})
|
||||
}
|
||||
Some(Token::TypedInt((n, t))) => {
|
||||
self.next();
|
||||
let end = self.peek_span().unwrap_or(start..start).end;
|
||||
Ok(Expr {
|
||||
kind: ExprKind::TypedInt(n, t),
|
||||
span: Span::new(&(start..end), self.file.clone()),
|
||||
attributes: Vec::new(),
|
||||
})
|
||||
}
|
||||
Some(Token::Float(f)) => {
|
||||
self.next();
|
||||
let end = self.peek_span().unwrap_or(start..start).end;
|
||||
|
|
@ -1607,25 +1693,44 @@ impl Parser {
|
|||
}
|
||||
Some(Token::LBracket) => {
|
||||
self.next();
|
||||
let mut elements = Vec::new();
|
||||
loop {
|
||||
if matches!(self.peek(), Some(Token::RBracket)) {
|
||||
self.next();
|
||||
break;
|
||||
}
|
||||
elements.push(self.parse_expr()?);
|
||||
|
||||
if matches!(self.peek(), Some(Token::Comma)) {
|
||||
self.next();
|
||||
let first_expr = self.parse_expr()?;
|
||||
if matches!(self.peek(), Some(Token::Semicolon)) {
|
||||
self.next();
|
||||
let size = match self.next() {
|
||||
Some((Token::Int(n), _)) => n,
|
||||
Some((_, span)) => {
|
||||
return self.error("Expected integer size for fixed array".to_string(), span);
|
||||
}
|
||||
None => {
|
||||
return self.error("Expected integer size for fixed array".to_string(), start..start);
|
||||
}
|
||||
};
|
||||
self.expect(Token::RBracket)?;
|
||||
let end = self.peek_span().unwrap_or(start..start).end;
|
||||
Ok(Expr {
|
||||
kind: ExprKind::FixedArray(Box::new(first_expr), size),
|
||||
span: Span::new(&(start..end), self.file.clone()),
|
||||
attributes: Vec::new(),
|
||||
})
|
||||
} else {
|
||||
let mut elements = vec![first_expr];
|
||||
loop {
|
||||
if matches!(self.peek(), Some(Token::RBracket)) {
|
||||
self.next();
|
||||
break;
|
||||
}
|
||||
if matches!(self.peek(), Some(Token::Comma)) {
|
||||
self.next();
|
||||
}
|
||||
elements.push(self.parse_expr()?);
|
||||
}
|
||||
let end = self.peek_span().unwrap_or(start..start).end;
|
||||
Ok(Expr {
|
||||
kind: ExprKind::Array(elements),
|
||||
span: Span::new(&(start..end), self.file.clone()),
|
||||
attributes: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
let end = self.peek_span().unwrap_or(start..start).end;
|
||||
Ok(Expr {
|
||||
kind: ExprKind::Array(elements),
|
||||
span: Span::new(&(start..end), self.file.clone()),
|
||||
attributes: Vec::new(),
|
||||
})
|
||||
}
|
||||
Some(Token::KeywordLet) => {
|
||||
self.next();
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ use std::fmt;
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Type {
|
||||
Int,
|
||||
U8,
|
||||
Float,
|
||||
Bool,
|
||||
String,
|
||||
Unit,
|
||||
Never,
|
||||
Array(Box<Type>),
|
||||
FixedArray(Box<Type>, usize),
|
||||
Ptr(Box<Type>),
|
||||
Tuple(Vec<Type>),
|
||||
Function(Vec<Type>, Box<Type>),
|
||||
|
|
@ -26,12 +28,14 @@ impl Type {
|
|||
pub fn to_string(&self) -> String {
|
||||
match self {
|
||||
Type::Int => "int".to_string(),
|
||||
Type::U8 => "u8".to_string(),
|
||||
Type::Float => "float".to_string(),
|
||||
Type::Bool => "bool".to_string(),
|
||||
Type::String => "string".to_string(),
|
||||
Type::Unit => "()".to_string(),
|
||||
Type::Never => "!".to_string(),
|
||||
Type::Array(inner) => format!("[{}]", inner.to_string()),
|
||||
Type::FixedArray(inner, size) => format!("[{}; {}]", inner.to_string(), size),
|
||||
Type::Ptr(inner) => format!("*{}", inner.to_string()),
|
||||
Type::Tuple(types) => {
|
||||
let type_strs: Vec<String> = types.iter().map(|t| t.to_string()).collect();
|
||||
|
|
@ -366,6 +370,351 @@ impl TypeChecker {
|
|||
}
|
||||
|
||||
fn add_builtin_functions(&mut self) {
|
||||
// Builtin types
|
||||
self.env.types.insert(
|
||||
"Vector3".to_string(),
|
||||
TypeInfo {
|
||||
kind: TypeInfoKind::Struct(vec![
|
||||
("x".to_string(), TypeAnnot::Var("float".to_string())),
|
||||
("y".to_string(), TypeAnnot::Var("float".to_string())),
|
||||
("z".to_string(), TypeAnnot::Var("float".to_string())),
|
||||
]),
|
||||
parameters: vec![],
|
||||
},
|
||||
);
|
||||
self.env.types.insert(
|
||||
"Color".to_string(),
|
||||
TypeInfo {
|
||||
kind: TypeInfoKind::Struct(vec![
|
||||
("r".to_string(), TypeAnnot::Var("u8".to_string())),
|
||||
("g".to_string(), TypeAnnot::Var("u8".to_string())),
|
||||
("b".to_string(), TypeAnnot::Var("u8".to_string())),
|
||||
("a".to_string(), TypeAnnot::Var("u8".to_string())),
|
||||
]),
|
||||
parameters: vec![],
|
||||
},
|
||||
);
|
||||
self.env.types.insert(
|
||||
"Shader".to_string(),
|
||||
TypeInfo {
|
||||
kind: TypeInfoKind::Struct(vec![
|
||||
("id".to_string(), TypeAnnot::Var("int".to_string())),
|
||||
]),
|
||||
parameters: vec![],
|
||||
},
|
||||
);
|
||||
self.env.types.insert(
|
||||
"Vector2".to_string(),
|
||||
TypeInfo {
|
||||
kind: TypeInfoKind::Struct(vec![
|
||||
("x".to_string(), TypeAnnot::Var("float".to_string())),
|
||||
("y".to_string(), TypeAnnot::Var("float".to_string())),
|
||||
]),
|
||||
parameters: vec![],
|
||||
},
|
||||
);
|
||||
self.env.types.insert(
|
||||
"sockaddr_in".to_string(),
|
||||
TypeInfo {
|
||||
kind: TypeInfoKind::Struct(vec![
|
||||
("sin_family".to_string(), TypeAnnot::Var("u16".to_string())),
|
||||
("sin_port".to_string(), TypeAnnot::Var("u16".to_string())),
|
||||
("sin_addr".to_string(), TypeAnnot::Cons("in_addr".to_string(), vec![])),
|
||||
("sin_zero".to_string(), TypeAnnot::FixedArray(Box::new(TypeAnnot::Var("u8".to_string())), 8)),
|
||||
]),
|
||||
parameters: vec![],
|
||||
},
|
||||
);
|
||||
|
||||
// Builtin functions
|
||||
// Raylib
|
||||
self.env.functions.insert(
|
||||
"init_window".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int, Type::Int, Type::String],
|
||||
return_type: Type::Unit,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"close_window".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![],
|
||||
return_type: Type::Unit,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"window_should_close".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![],
|
||||
return_type: Type::Bool,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"set_target_fps".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int],
|
||||
return_type: Type::Unit,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"disable_cursor".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![],
|
||||
return_type: Type::Unit,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"get_char_pressed".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![],
|
||||
return_type: Type::Int,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"is_key_pressed".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int],
|
||||
return_type: Type::Bool,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"is_key_down".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int],
|
||||
return_type: Type::Bool,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"get_mouse_delta".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![],
|
||||
return_type: Type::Struct("Vector2".to_string(), vec![]),
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"is_mouse_button_down".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int],
|
||||
return_type: Type::Bool,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"get_random_value".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int, Type::Int],
|
||||
return_type: Type::Int,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"get_frame_time".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"begin_drawing".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![],
|
||||
return_type: Type::Unit,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"end_drawing".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![],
|
||||
return_type: Type::Unit,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"clear_background".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int, Type::Int, Type::Int, Type::Int],
|
||||
return_type: Type::Unit,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"draw_text".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::String, Type::Int, Type::Int, Type::Int, Type::Int, Type::Int, Type::Int, Type::Int],
|
||||
return_type: Type::Unit,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"draw_fps".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int, Type::Int],
|
||||
return_type: Type::Unit,
|
||||
},
|
||||
);
|
||||
|
||||
// Math functions
|
||||
self.env.functions.insert(
|
||||
"sinf".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"cosf".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"sqrtf".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"fmaxf".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float, Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"floorf".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"powf".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float, Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"expf".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
|
||||
// Noise functions
|
||||
self.env.functions.insert(
|
||||
"grad2".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int, Type::Float, Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"simplex_noise_2d".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float, Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"fbm_noise".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float, Type::Float, Type::Int],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"get_terrain_height".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Float, Type::Float],
|
||||
return_type: Type::Float,
|
||||
},
|
||||
);
|
||||
|
||||
// Socket functions
|
||||
self.env.functions.insert(
|
||||
"socket".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int, Type::Int, Type::Int],
|
||||
return_type: Type::Int,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"sendto".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int, Type::Ptr(Box::new(Type::U8)), Type::Int, Type::Int, Type::Ptr(Box::new(Type::Unit)), Type::Int],
|
||||
return_type: Type::Int,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"recvfrom".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int, Type::Ptr(Box::new(Type::U8)), Type::Int, Type::Int, Type::Ptr(Box::new(Type::Unit)), Type::Ptr(Box::new(Type::Int))],
|
||||
return_type: Type::Int,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"close".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int],
|
||||
return_type: Type::Int,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"htonl".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int],
|
||||
return_type: Type::Int,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"htons".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int],
|
||||
return_type: Type::Int,
|
||||
},
|
||||
);
|
||||
self.env.functions.insert(
|
||||
"inet_pton".to_string(),
|
||||
FunctionType {
|
||||
type_params: vec![],
|
||||
params: vec![Type::Int, Type::String, Type::Ptr(Box::new(Type::Unit))],
|
||||
return_type: Type::Int,
|
||||
},
|
||||
);
|
||||
|
||||
// ODE Physics Engine functions
|
||||
self.env.functions.insert(
|
||||
"ode_init".to_string(),
|
||||
|
|
@ -1560,6 +1909,19 @@ impl TypeChecker {
|
|||
|
||||
fn typecheck_node(&mut self, node: &ASTNode) -> Result<TypedASTNode, TypeError> {
|
||||
let ty = match &node.kind {
|
||||
ASTNodeKind::Const(c) => {
|
||||
let typed_value = self.typecheck_expr(&c.value)?;
|
||||
return Ok(TypedASTNode {
|
||||
kind: TypedASTNodeKind::Const(TypedConst {
|
||||
name: c.name.clone(),
|
||||
typ: c.typ.clone(),
|
||||
value: typed_value.clone(),
|
||||
}),
|
||||
span: node.span.clone(),
|
||||
attributes: node.attributes.clone(),
|
||||
ty: typed_value.ty,
|
||||
});
|
||||
}
|
||||
ASTNodeKind::Function(f) => {
|
||||
let typed_func = self.typecheck_function(f)?;
|
||||
let ty = typed_func.ty.clone();
|
||||
|
|
@ -1761,6 +2123,16 @@ impl TypeChecker {
|
|||
fn typecheck_expr(&mut self, expr: &Expr) -> Result<TypedExpr, TypeError> {
|
||||
let (kind, ty) = match &expr.kind {
|
||||
ExprKind::Int(n) => (TypedExprKind::Int(*n), Type::Int),
|
||||
ExprKind::TypedInt(n, t) => {
|
||||
let ty = match t.as_str() {
|
||||
"u8" => Type::U8,
|
||||
_ => return Err(TypeError {
|
||||
kind: TypeErrorKind::UndefinedType(t.clone()),
|
||||
span: expr.span.clone(),
|
||||
}),
|
||||
};
|
||||
(TypedExprKind::TypedInt(*n, t.clone()), ty)
|
||||
},
|
||||
ExprKind::Float(f) => (TypedExprKind::Float(*f), Type::Float),
|
||||
ExprKind::Bool(b) => (TypedExprKind::Bool(*b), Type::Bool),
|
||||
ExprKind::String(s) => (TypedExprKind::String(s.clone()), Type::String),
|
||||
|
|
@ -1814,6 +2186,14 @@ impl TypeChecker {
|
|||
)
|
||||
}
|
||||
|
||||
ExprKind::FixedArray(expr, size) => {
|
||||
let typed_expr = self.typecheck_expr(expr)?;
|
||||
(
|
||||
TypedExprKind::FixedArray(Box::new(typed_expr.clone()), *size as usize),
|
||||
Type::FixedArray(Box::new(typed_expr.ty), *size as usize),
|
||||
)
|
||||
}
|
||||
|
||||
ExprKind::Tuple(elements) => {
|
||||
let mut typed_elements = Vec::new();
|
||||
let mut types = Vec::new();
|
||||
|
|
@ -1840,7 +2220,7 @@ impl TypeChecker {
|
|||
let typed_right = self.typecheck_expr(right)?;
|
||||
|
||||
let result_type = match op {
|
||||
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Mod | BinOp::BitwiseAnd | BinOp::BitwiseOr => {
|
||||
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Mod | BinOp::BitwiseAnd | BinOp::BitwiseOr | BinOp::LShift | BinOp::RShift => {
|
||||
if !self.types_compatible(&typed_left.ty, &typed_right.ty) {
|
||||
return Err(TypeError {
|
||||
kind: TypeErrorKind::TypeMismatch(
|
||||
|
|
@ -2171,7 +2551,7 @@ impl TypeChecker {
|
|||
}
|
||||
|
||||
let element_type = match &typed_array.ty {
|
||||
Type::Array(elem_ty) => (**elem_ty).clone(),
|
||||
Type::Array(elem_ty) | Type::FixedArray(elem_ty, _) => (**elem_ty).clone(),
|
||||
ty => {
|
||||
return Err(TypeError {
|
||||
kind: TypeErrorKind::NotAnArray(ty.clone()),
|
||||
|
|
@ -2836,13 +3216,14 @@ impl TypeChecker {
|
|||
TypeInfoKind::Enum(_) => Type::Enum(name.clone(), substituted_args),
|
||||
}
|
||||
} else {
|
||||
match name.as_str() {
|
||||
"int" => Type::Int,
|
||||
"float" => Type::Float,
|
||||
"bool" => Type::Bool,
|
||||
"string" => Type::String,
|
||||
"unit" => Type::Unit,
|
||||
"never" => Type::Never,
|
||||
match name.as_str() {
|
||||
"int" => Type::Int,
|
||||
"u8" => Type::U8,
|
||||
"float" => Type::Float,
|
||||
"bool" => Type::Bool,
|
||||
"string" => Type::String,
|
||||
"unit" => Type::Unit,
|
||||
"never" => Type::Never,
|
||||
_ => Type::Generic(name.clone(), substituted_args),
|
||||
}
|
||||
}
|
||||
|
|
@ -2850,6 +3231,9 @@ impl TypeChecker {
|
|||
TypeAnnot::Array(inner) => {
|
||||
Type::Array(Box::new(self.substitute_type(inner, subst_map)))
|
||||
}
|
||||
TypeAnnot::FixedArray(inner, size) => {
|
||||
Type::FixedArray(Box::new(self.substitute_type(inner, subst_map)), *size as usize)
|
||||
}
|
||||
TypeAnnot::Ptr(inner) => Type::Ptr(Box::new(self.substitute_type(inner, subst_map))),
|
||||
TypeAnnot::Tuple(types) => {
|
||||
let substituted_types: Vec<Type> = types
|
||||
|
|
@ -2893,6 +3277,7 @@ impl TypeChecker {
|
|||
|
||||
match name.as_str() {
|
||||
"int" => Type::Int,
|
||||
"u8" => Type::U8,
|
||||
"float" => Type::Float,
|
||||
"bool" => Type::Bool,
|
||||
"string" => Type::String,
|
||||
|
|
@ -2923,6 +3308,7 @@ impl TypeChecker {
|
|||
Type::Tuple(tuple_types)
|
||||
}
|
||||
TypeAnnot::Array(inner) => Type::Array(Box::new(self.type_annot_to_type(inner))),
|
||||
TypeAnnot::FixedArray(inner, size) => Type::FixedArray(Box::new(self.type_annot_to_type(inner)), *size as usize),
|
||||
TypeAnnot::Ptr(inner) => Type::Ptr(Box::new(self.type_annot_to_type(inner))),
|
||||
}
|
||||
}
|
||||
|
|
@ -2931,12 +3317,14 @@ impl TypeChecker {
|
|||
match (t1, t2) {
|
||||
(Type::Unknown, _) | (_, Type::Unknown) => true,
|
||||
(Type::Int, Type::Int) => true,
|
||||
(Type::U8, Type::U8) => true,
|
||||
(Type::Float, Type::Float) => true,
|
||||
(Type::Bool, Type::Bool) => true,
|
||||
(Type::String, Type::String) => true,
|
||||
(Type::Unit, Type::Unit) => true,
|
||||
(Type::Never, _) | (_, Type::Never) => true,
|
||||
(Type::Array(a), Type::Array(b)) => self.types_compatible(a, b),
|
||||
(Type::FixedArray(a, s1), Type::FixedArray(b, s2)) => s1 == s2 && 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()
|
||||
|
|
|
|||
47
tests/fixed_arrays.c
Normal file
47
tests/fixed_arrays.c
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#include "libsuicmez/libsuicmez.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
void* gc_alloc(const TypeInfo* type, size_t size);
|
||||
void gc_init(void);
|
||||
void gc_shutdown(void);
|
||||
|
||||
// Helper for allocating arrays
|
||||
static void* suic_alloc_array(const TypeInfo* type, size_t elem_size, size_t len, void* init_data) {
|
||||
void* ptr = gc_alloc(type, elem_size * len);
|
||||
if (init_data) memcpy(ptr, init_data, elem_size * len);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Helper for allocating structs
|
||||
static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_data) {
|
||||
void* ptr = gc_alloc(type, size);
|
||||
if (init_data) memcpy(ptr, init_data, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int suic_main(void);
|
||||
|
||||
|
||||
int suic_main(void) {
|
||||
int arr[5] = {42, 42, 42, 42, 42};
|
||||
int x = arr[2];
|
||||
return x;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Initialize GC
|
||||
gc_init();
|
||||
// init globals
|
||||
// init event loop
|
||||
int result = suic_main();
|
||||
// Shutdown GC
|
||||
gc_shutdown();
|
||||
return result;
|
||||
}
|
||||
|
||||
BIN
tests/fixed_arrays.o
Executable file
BIN
tests/fixed_arrays.o
Executable file
Binary file not shown.
6
tests/fixed_arrays.sui
Normal file
6
tests/fixed_arrays.sui
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Fixed array test
|
||||
fn main() -> int do
|
||||
let arr: [int; 5] = [42; 5];
|
||||
let x = arr[2];
|
||||
x
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue