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>),
|
Function(Vec<TypeAnnot>, Box<TypeAnnot>),
|
||||||
Tuple(Vec<TypeAnnot>),
|
Tuple(Vec<TypeAnnot>),
|
||||||
Array(Box<TypeAnnot>),
|
Array(Box<TypeAnnot>),
|
||||||
|
FixedArray(Box<TypeAnnot>, i64),
|
||||||
Ptr(Box<TypeAnnot>),
|
Ptr(Box<TypeAnnot>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,6 +67,7 @@ pub enum ASTNodeKind {
|
||||||
Function(Function),
|
Function(Function),
|
||||||
Extern(Extern),
|
Extern(Extern),
|
||||||
Load(Load),
|
Load(Load),
|
||||||
|
Const(Const),
|
||||||
Struct(Struct),
|
Struct(Struct),
|
||||||
Enum(Enum),
|
Enum(Enum),
|
||||||
Impl(Impl),
|
Impl(Impl),
|
||||||
|
|
@ -79,6 +81,13 @@ pub struct Use {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Const {
|
||||||
|
pub name: String,
|
||||||
|
pub typ: Option<TypeAnnot>,
|
||||||
|
pub value: Expr,
|
||||||
|
}
|
||||||
|
|
||||||
// ? implies OPTIONAL here
|
// ? implies OPTIONAL here
|
||||||
// \( implies the presence of (. same for /)
|
// \( implies the presence of (. same for /)
|
||||||
|
|
||||||
|
|
@ -204,10 +213,12 @@ pub struct Expr {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ExprKind {
|
pub enum ExprKind {
|
||||||
Int(i64),
|
Int(i64),
|
||||||
|
TypedInt(i64, String),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
String(String),
|
String(String),
|
||||||
Array(Vec<Expr>),
|
Array(Vec<Expr>),
|
||||||
|
FixedArray(Box<Expr>, i64),
|
||||||
Tuple(Vec<Expr>),
|
Tuple(Vec<Expr>),
|
||||||
|
|
||||||
StructLit(String, Vec<(String, Expr)>), // Name { a: expr, b: expr }
|
StructLit(String, Vec<(String, Expr)>), // Name { a: expr, b: expr }
|
||||||
|
|
@ -262,6 +273,8 @@ pub enum BinOp {
|
||||||
Or,
|
Or,
|
||||||
BitwiseAnd,
|
BitwiseAnd,
|
||||||
BitwiseOr,
|
BitwiseOr,
|
||||||
|
LShift,
|
||||||
|
RShift,
|
||||||
Eq,
|
Eq,
|
||||||
Neq,
|
Neq,
|
||||||
Lt,
|
Lt,
|
||||||
|
|
@ -311,6 +324,7 @@ pub enum TypedASTNodeKind {
|
||||||
Function(TypedFunction),
|
Function(TypedFunction),
|
||||||
Extern(TypedExtern),
|
Extern(TypedExtern),
|
||||||
Load(TypedLoad),
|
Load(TypedLoad),
|
||||||
|
Const(TypedConst),
|
||||||
Struct(TypedStruct),
|
Struct(TypedStruct),
|
||||||
Enum(TypedEnum),
|
Enum(TypedEnum),
|
||||||
Impl(TypedImpl),
|
Impl(TypedImpl),
|
||||||
|
|
@ -344,6 +358,13 @@ pub struct TypedLoad {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TypedConst {
|
||||||
|
pub name: String,
|
||||||
|
pub typ: Option<TypeAnnot>,
|
||||||
|
pub value: TypedExpr,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TypedStruct {
|
pub struct TypedStruct {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
@ -398,10 +419,12 @@ pub struct TypedExpr {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TypedExprKind {
|
pub enum TypedExprKind {
|
||||||
Int(i64),
|
Int(i64),
|
||||||
|
TypedInt(i64, String),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
String(String),
|
String(String),
|
||||||
Array(Vec<TypedExpr>),
|
Array(Vec<TypedExpr>),
|
||||||
|
FixedArray(Box<TypedExpr>, usize),
|
||||||
Tuple(Vec<TypedExpr>),
|
Tuple(Vec<TypedExpr>),
|
||||||
StructLit(String, Vec<(String, TypedExpr)>),
|
StructLit(String, Vec<(String, TypedExpr)>),
|
||||||
EnumLit(String, String, Vec<TypedExpr>),
|
EnumLit(String, String, Vec<TypedExpr>),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
pub enum CType {
|
pub enum CType {
|
||||||
Void,
|
Void,
|
||||||
Int,
|
Int,
|
||||||
|
U8,
|
||||||
Float,
|
Float,
|
||||||
Bool,
|
Bool,
|
||||||
Char,
|
Char,
|
||||||
|
|
@ -9,6 +10,7 @@ pub enum CType {
|
||||||
Struct(String),
|
Struct(String),
|
||||||
UnnamedStruct(Vec<CVarDecl>),
|
UnnamedStruct(Vec<CVarDecl>),
|
||||||
Array(Box<CType>), // heap-allocated array wrapper with data pointer, len, capacity
|
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
|
Func(Vec<CType>, Box<CType>), // args and return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,6 +34,7 @@ impl CType {
|
||||||
match self {
|
match self {
|
||||||
CType::Void => "void".to_string(),
|
CType::Void => "void".to_string(),
|
||||||
CType::Int => "int".to_string(),
|
CType::Int => "int".to_string(),
|
||||||
|
CType::U8 => "uint8_t".to_string(),
|
||||||
CType::Float => "float".to_string(),
|
CType::Float => "float".to_string(),
|
||||||
CType::Bool => "bool".to_string(),
|
CType::Bool => "bool".to_string(),
|
||||||
CType::Char => "char".to_string(),
|
CType::Char => "char".to_string(),
|
||||||
|
|
@ -48,6 +51,7 @@ impl CType {
|
||||||
"struct sui_array_{}",
|
"struct sui_array_{}",
|
||||||
inner.to_string().replace(" ", "_").replace("*", "ptr")
|
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) => {
|
CType::Func(args, ret) => {
|
||||||
let arg_strs: Vec<String> = args.iter().map(|t| t.to_string()).collect();
|
let arg_strs: Vec<String> = args.iter().map(|t| t.to_string()).collect();
|
||||||
format!("{} (*)({})", ret.to_string(), arg_strs.join(", "))
|
format!("{} (*)({})", ret.to_string(), arg_strs.join(", "))
|
||||||
|
|
@ -61,6 +65,7 @@ pub struct CVarDecl {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub ty: CType,
|
pub ty: CType,
|
||||||
pub initializer: Option<CExpr>,
|
pub initializer: Option<CExpr>,
|
||||||
|
pub is_const: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
|
@ -116,6 +121,8 @@ pub enum CBinaryOp {
|
||||||
Or,
|
Or,
|
||||||
BitwiseAnd,
|
BitwiseAnd,
|
||||||
BitwiseOr,
|
BitwiseOr,
|
||||||
|
LShift,
|
||||||
|
RShift,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CBinaryOp {
|
impl CBinaryOp {
|
||||||
|
|
@ -136,6 +143,8 @@ impl CBinaryOp {
|
||||||
CBinaryOp::Or => "||",
|
CBinaryOp::Or => "||",
|
||||||
CBinaryOp::BitwiseAnd => "&",
|
CBinaryOp::BitwiseAnd => "&",
|
||||||
CBinaryOp::BitwiseOr => "|",
|
CBinaryOp::BitwiseOr => "|",
|
||||||
|
CBinaryOp::LShift => "<<",
|
||||||
|
CBinaryOp::RShift => ">>",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ impl DeclarationTranspiler {
|
||||||
name: field.name.clone(),
|
name: field.name.clone(),
|
||||||
ty: field_type,
|
ty: field_type,
|
||||||
initializer: None,
|
initializer: None,
|
||||||
|
is_const: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,6 +54,7 @@ impl DeclarationTranspiler {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
ty: param_type,
|
ty: param_type,
|
||||||
initializer: None,
|
initializer: None,
|
||||||
|
is_const: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,6 +83,7 @@ impl DeclarationTranspiler {
|
||||||
name: field_name,
|
name: field_name,
|
||||||
ty: c_type,
|
ty: c_type,
|
||||||
initializer: None,
|
initializer: None,
|
||||||
|
is_const: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,6 +103,7 @@ impl DeclarationTranspiler {
|
||||||
name: field_name,
|
name: field_name,
|
||||||
ty: CType::Struct(struct_name),
|
ty: CType::Struct(struct_name),
|
||||||
initializer: None,
|
initializer: None,
|
||||||
|
is_const: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,11 +119,13 @@ impl DeclarationTranspiler {
|
||||||
name: "discriminant".to_string(),
|
name: "discriminant".to_string(),
|
||||||
ty: CType::Int,
|
ty: CType::Int,
|
||||||
initializer: None,
|
initializer: None,
|
||||||
|
is_const: false,
|
||||||
},
|
},
|
||||||
CVarDecl {
|
CVarDecl {
|
||||||
name: "data".to_string(),
|
name: "data".to_string(),
|
||||||
ty: CType::Struct(union_name_clone),
|
ty: CType::Struct(union_name_clone),
|
||||||
initializer: None,
|
initializer: None,
|
||||||
|
is_const: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -148,6 +154,10 @@ impl DeclarationTranspiler {
|
||||||
// Arrays are pointers to the element type
|
// Arrays are pointers to the element type
|
||||||
Ok(CType::Ptr(Box::new(inner_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)) => {
|
Some(TypeAnnot::Tuple(fields)) => {
|
||||||
let mut c_fields = Vec::new();
|
let mut c_fields = Vec::new();
|
||||||
for (i, field_annot) in fields.iter().enumerate() {
|
for (i, field_annot) in fields.iter().enumerate() {
|
||||||
|
|
@ -156,6 +166,7 @@ impl DeclarationTranspiler {
|
||||||
name: format!("field{}", i),
|
name: format!("field{}", i),
|
||||||
ty: field_type,
|
ty: field_type,
|
||||||
initializer: None,
|
initializer: None,
|
||||||
|
is_const: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(CType::UnnamedStruct(c_fields))
|
Ok(CType::UnnamedStruct(c_fields))
|
||||||
|
|
@ -176,6 +187,7 @@ impl DeclarationTranspiler {
|
||||||
pub fn convert_to_c_type(name: &String) -> Result<CType, String> {
|
pub fn convert_to_c_type(name: &String) -> Result<CType, String> {
|
||||||
match String::as_str(name) {
|
match String::as_str(name) {
|
||||||
"int" => Ok(CType::Int),
|
"int" => Ok(CType::Int),
|
||||||
|
"u8" => Ok(CType::U8),
|
||||||
"float" => Ok(CType::Float),
|
"float" => Ok(CType::Float),
|
||||||
"bool" => Ok(CType::Bool),
|
"bool" => Ok(CType::Bool),
|
||||||
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
|
"string" => Ok(CType::Ptr(Box::new(CType::Char))),
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ impl StatementsTranspiler {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
ty,
|
ty,
|
||||||
initializer,
|
initializer,
|
||||||
|
is_const: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
(name, decl)
|
(name, decl)
|
||||||
|
|
@ -48,6 +49,13 @@ impl StatementsTranspiler {
|
||||||
pub fn transpile_expr(&self, expr: &TypedExpr) -> Result<CExpr, String> {
|
pub fn transpile_expr(&self, expr: &TypedExpr) -> Result<CExpr, String> {
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
TypedExprKind::Int(i) => Ok(CExpr::IntLit(*i)),
|
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::Float(f) => Ok(CExpr::FloatLit(*f)),
|
||||||
TypedExprKind::Bool(b) => Ok(CExpr::BoolLit(*b)),
|
TypedExprKind::Bool(b) => Ok(CExpr::BoolLit(*b)),
|
||||||
TypedExprKind::String(s) => Ok(CExpr::StringLit(s.clone())),
|
TypedExprKind::String(s) => Ok(CExpr::StringLit(s.clone())),
|
||||||
|
|
@ -117,6 +125,11 @@ impl StatementsTranspiler {
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
Ok(CExpr::ArrayLit(c_exprs))
|
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) => {
|
TypedExprKind::Cast(expr, type_annot) => {
|
||||||
let c_expr = self.transpile_expr(expr)?;
|
let c_expr = self.transpile_expr(expr)?;
|
||||||
// Simplified: assuming we can map type annotations to C types
|
// Simplified: assuming we can map type annotations to C types
|
||||||
|
|
@ -170,6 +183,7 @@ impl StatementsTranspiler {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
ty: c_type,
|
ty: c_type,
|
||||||
initializer,
|
initializer,
|
||||||
|
is_const: false,
|
||||||
};
|
};
|
||||||
Ok(CStmt::VarDecl(var_decl))
|
Ok(CStmt::VarDecl(var_decl))
|
||||||
}
|
}
|
||||||
|
|
@ -221,6 +235,7 @@ impl StatementsTranspiler {
|
||||||
name: var_name.clone(),
|
name: var_name.clone(),
|
||||||
ty: CType::Int,
|
ty: CType::Int,
|
||||||
initializer: Some(start_expr),
|
initializer: Some(start_expr),
|
||||||
|
is_const: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let cond = CExpr::BinOp(
|
let cond = CExpr::BinOp(
|
||||||
|
|
@ -272,6 +287,7 @@ impl StatementsTranspiler {
|
||||||
)),
|
)),
|
||||||
Box::new(CExpr::Var(idx_name.clone())),
|
Box::new(CExpr::Var(idx_name.clone())),
|
||||||
)),
|
)),
|
||||||
|
is_const: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut body_stmts = vec![bind];
|
let mut body_stmts = vec![bind];
|
||||||
|
|
@ -321,6 +337,7 @@ impl StatementsTranspiler {
|
||||||
Box::new(CExpr::Var(arr_name.clone())),
|
Box::new(CExpr::Var(arr_name.clone())),
|
||||||
Box::new(CExpr::Var(idx_name.clone())),
|
Box::new(CExpr::Var(idx_name.clone())),
|
||||||
)),
|
)),
|
||||||
|
is_const: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut body_stmts = vec![bind];
|
let mut body_stmts = vec![bind];
|
||||||
|
|
@ -456,6 +473,8 @@ impl StatementsTranspiler {
|
||||||
BinOp::Or => Ok(CBinaryOp::Or),
|
BinOp::Or => Ok(CBinaryOp::Or),
|
||||||
BinOp::BitwiseAnd => Ok(CBinaryOp::BitwiseAnd),
|
BinOp::BitwiseAnd => Ok(CBinaryOp::BitwiseAnd),
|
||||||
BinOp::BitwiseOr => Ok(CBinaryOp::BitwiseOr),
|
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 {
|
match ty {
|
||||||
Type::Int => Ok(CType::Int),
|
Type::Int => Ok(CType::Int),
|
||||||
|
Type::U8 => Ok(CType::U8),
|
||||||
Type::Float => Ok(CType::Float),
|
Type::Float => Ok(CType::Float),
|
||||||
Type::Bool => Ok(CType::Bool),
|
Type::Bool => Ok(CType::Bool),
|
||||||
Type::String => Ok(CType::Ptr(Box::new(CType::Char))),
|
Type::String => Ok(CType::Ptr(Box::new(CType::Char))),
|
||||||
|
|
@ -482,6 +502,10 @@ impl StatementsTranspiler {
|
||||||
// Arrays are pointers to the element type
|
// Arrays are pointers to the element type
|
||||||
Ok(CType::Ptr(Box::new(inner_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::Struct(name, _) => Ok(CType::Ptr(Box::new(CType::Struct(name.clone())))),
|
||||||
Type::Enum(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) => {
|
Type::Tuple(types) => {
|
||||||
|
|
@ -492,6 +516,7 @@ impl StatementsTranspiler {
|
||||||
name: format!("field{}", i),
|
name: format!("field{}", i),
|
||||||
ty: c_type,
|
ty: c_type,
|
||||||
initializer: None,
|
initializer: None,
|
||||||
|
is_const: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(CType::UnnamedStruct(fields))
|
Ok(CType::UnnamedStruct(fields))
|
||||||
|
|
@ -536,6 +561,10 @@ impl StatementsTranspiler {
|
||||||
// Arrays are pointers to the element type
|
// Arrays are pointers to the element type
|
||||||
Ok(CType::Ptr(Box::new(inner_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) => {
|
TypeAnnot::Tuple(fields) => {
|
||||||
let mut c_fields = Vec::new();
|
let mut c_fields = Vec::new();
|
||||||
for (i, field_annot) in fields.iter().enumerate() {
|
for (i, field_annot) in fields.iter().enumerate() {
|
||||||
|
|
@ -544,6 +573,7 @@ impl StatementsTranspiler {
|
||||||
name: format!("field{}", i),
|
name: format!("field{}", i),
|
||||||
ty: field_type,
|
ty: field_type,
|
||||||
initializer: None,
|
initializer: None,
|
||||||
|
is_const: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(CType::UnnamedStruct(c_fields))
|
Ok(CType::UnnamedStruct(c_fields))
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,39 @@ impl Transpiler {
|
||||||
self.lower_declarations_to_c_ir(node)?;
|
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)?;
|
self.lower_function_bodies_to_c_ir(nodes)?;
|
||||||
|
|
||||||
// Rename main to suic_main and track that we have a main
|
// Rename main to suic_main and track that we have a main
|
||||||
|
|
@ -238,6 +271,16 @@ impl Transpiler {
|
||||||
self.functions.push(func_decl);
|
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) => {
|
TypedASTNodeKind::Extern(e) => {
|
||||||
// For externs, we might need to add function prototypes
|
// For externs, we might need to add function prototypes
|
||||||
// But for now, skip as they're handled differently
|
// But for now, skip as they're handled differently
|
||||||
|
|
@ -404,9 +447,26 @@ impl Transpiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_var_decl(&self, var: &CVarDecl) -> String {
|
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 {
|
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
|
output
|
||||||
}
|
}
|
||||||
|
|
@ -638,13 +698,14 @@ impl Transpiler {
|
||||||
"rl_pop_matrix" => "suic_rl_pop_matrix",
|
"rl_pop_matrix" => "suic_rl_pop_matrix",
|
||||||
"rl_translate_f" => "suic_rl_translate_f",
|
"rl_translate_f" => "suic_rl_translate_f",
|
||||||
"rl_rotate_f" => "suic_rl_rotate_f",
|
"rl_rotate_f" => "suic_rl_rotate_f",
|
||||||
// UI Framework Utils
|
// UI Framework Utils
|
||||||
"draw_text" => "suic_draw_text",
|
"draw_text" => "DrawText",
|
||||||
"draw_rectangle" => "suic_draw_rectangle",
|
"draw_rectangle" => "DrawRectangle",
|
||||||
"draw_rectangle_lines" => "suic_draw_rectangle_lines",
|
"draw_rectangle_lines" => "DrawRectangleLines",
|
||||||
"measure_text" => "suic_measure_text",
|
"measure_text" => "MeasureText",
|
||||||
"draw_circle" => "suic_draw_circle",
|
"draw_circle" => "DrawCircle",
|
||||||
"draw_line" => "suic_draw_line",
|
"draw_line" => "DrawLine",
|
||||||
|
"draw_fps" => "DrawFPS",
|
||||||
// Player controller functions
|
// Player controller functions
|
||||||
"player_controller_create" => "suic_player_controller_create",
|
"player_controller_create" => "suic_player_controller_create",
|
||||||
"player_controller_destroy" => "suic_player_controller_destroy",
|
"player_controller_destroy" => "suic_player_controller_destroy",
|
||||||
|
|
@ -735,18 +796,7 @@ impl Transpiler {
|
||||||
"Vec3" => "suic_vec3".to_string(),
|
"Vec3" => "suic_vec3".to_string(),
|
||||||
_ => format!("struct {}", struct_name),
|
_ => format!("struct {}", struct_name),
|
||||||
};
|
};
|
||||||
// For built-in simple structs, generate compound literal directly
|
format!("({}){{ {} }}", c_type_name, field_inits.join(", "))
|
||||||
// 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(", ")
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
CExpr::EnumLit(enum_name, variant_name, args) => {
|
CExpr::EnumLit(enum_name, variant_name, args) => {
|
||||||
// Find the variant index - for simplicity, assume variants are in order
|
// Find the variant index - for simplicity, assume variants are in order
|
||||||
|
|
|
||||||
|
|
@ -370,14 +370,22 @@ impl ImportResolver {
|
||||||
ASTNodeKind::Load(_) => {
|
ASTNodeKind::Load(_) => {
|
||||||
result.push(node);
|
result.push(node);
|
||||||
}
|
}
|
||||||
ASTNodeKind::Trait(t) => {
|
ASTNodeKind::Trait(t) => {
|
||||||
self.symbol_registry.register(
|
self.symbol_registry.register(
|
||||||
t.name.clone(),
|
t.name.clone(),
|
||||||
filename.to_string(),
|
filename.to_string(),
|
||||||
node.span.clone(),
|
node.span.clone(),
|
||||||
)?;
|
)?;
|
||||||
result.push(node);
|
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);
|
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) => {
|
ExprKind::Tuple(exprs) => {
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
self.collect_free_vars_expr(expr, lambda_params, free_vars, local_scope);
|
||||||
|
|
@ -150,6 +153,7 @@ impl LambdaLowerer {
|
||||||
}
|
}
|
||||||
// Terminal expressions don't contain variables
|
// Terminal expressions don't contain variables
|
||||||
ExprKind::Int(_)
|
ExprKind::Int(_)
|
||||||
|
| ExprKind::TypedInt(_, _)
|
||||||
| ExprKind::Float(_)
|
| ExprKind::Float(_)
|
||||||
| ExprKind::Bool(_)
|
| ExprKind::Bool(_)
|
||||||
| ExprKind::String(_)
|
| ExprKind::String(_)
|
||||||
|
|
@ -340,6 +344,10 @@ impl LambdaLowerer {
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
ExprKind::Array(lowered_exprs)
|
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) => {
|
ExprKind::Tuple(exprs) => {
|
||||||
let lowered_exprs = exprs
|
let lowered_exprs = exprs
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -369,6 +377,7 @@ impl LambdaLowerer {
|
||||||
}
|
}
|
||||||
// Terminal expressions that don't contain other expressions
|
// Terminal expressions that don't contain other expressions
|
||||||
ExprKind::Int(_)
|
ExprKind::Int(_)
|
||||||
|
| ExprKind::TypedInt(_, _)
|
||||||
| ExprKind::Float(_)
|
| ExprKind::Float(_)
|
||||||
| ExprKind::Bool(_)
|
| ExprKind::Bool(_)
|
||||||
| ExprKind::String(_)
|
| ExprKind::String(_)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,14 @@ pub enum Token {
|
||||||
}, priority = 4)]
|
}, priority = 4)]
|
||||||
Int(i64),
|
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| {
|
#[regex(r"(([0-9][0-9_]*\.[0-9_]+|[0-9]*\.[0-9_]+)([eE][+-]?[0-9_]+)?)", |lex| {
|
||||||
let s = lex.slice().replace("_", "");
|
let s = lex.slice().replace("_", "");
|
||||||
s.parse::<f64>().unwrap()
|
s.parse::<f64>().unwrap()
|
||||||
|
|
@ -61,6 +69,9 @@ pub enum Token {
|
||||||
#[token("string")]
|
#[token("string")]
|
||||||
KeywordString,
|
KeywordString,
|
||||||
|
|
||||||
|
#[token("u8")]
|
||||||
|
KeywordU8,
|
||||||
|
|
||||||
#[token("let")]
|
#[token("let")]
|
||||||
KeywordLet,
|
KeywordLet,
|
||||||
|
|
||||||
|
|
@ -135,6 +146,9 @@ pub enum Token {
|
||||||
#[token("trait")]
|
#[token("trait")]
|
||||||
KeywordTrait,
|
KeywordTrait,
|
||||||
|
|
||||||
|
#[token("const")]
|
||||||
|
KeywordConst,
|
||||||
|
|
||||||
// #[token("type")]
|
// #[token("type")]
|
||||||
// KeywordType,
|
// KeywordType,
|
||||||
//
|
//
|
||||||
|
|
@ -171,6 +185,12 @@ pub enum Token {
|
||||||
#[token("**", priority = 3)]
|
#[token("**", priority = 3)]
|
||||||
Power,
|
Power,
|
||||||
|
|
||||||
|
#[token("<<")]
|
||||||
|
LShift,
|
||||||
|
|
||||||
|
#[token(">>")]
|
||||||
|
RShift,
|
||||||
|
|
||||||
#[token("$")]
|
#[token("$")]
|
||||||
Dollar,
|
Dollar,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,9 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> {
|
||||||
suicmez::ast::TypedASTNodeKind::Function(f) => {
|
suicmez::ast::TypedASTNodeKind::Function(f) => {
|
||||||
format!("Function({})", f.name)
|
format!("Function({})", f.name)
|
||||||
}
|
}
|
||||||
|
suicmez::ast::TypedASTNodeKind::Const(c) => {
|
||||||
|
format!("Const({})", c.name)
|
||||||
|
}
|
||||||
suicmez::ast::TypedASTNodeKind::Struct(s) => {
|
suicmez::ast::TypedASTNodeKind::Struct(s) => {
|
||||||
format!("Struct({}) with {} params", s.name, s.parameters.len())
|
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) => {
|
suicmez::ast::TypedASTNodeKind::Function(f) => {
|
||||||
format!("Function({})", f.name)
|
format!("Function({})", f.name)
|
||||||
}
|
}
|
||||||
|
suicmez::ast::TypedASTNodeKind::Const(c) => {
|
||||||
|
format!("Const({})", c.name)
|
||||||
|
}
|
||||||
suicmez::ast::TypedASTNodeKind::Struct(s) => {
|
suicmez::ast::TypedASTNodeKind::Struct(s) => {
|
||||||
format!("Struct({}) with {} params", s.name, s.parameters.len())
|
format!("Struct({}) with {} params", s.name, s.parameters.len())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,9 @@ impl Monomorphizer {
|
||||||
|
|
||||||
for (_idx, node) in nodes.iter().enumerate() {
|
for (_idx, node) in nodes.iter().enumerate() {
|
||||||
match &node.kind {
|
match &node.kind {
|
||||||
|
TypedASTNodeKind::Const(c) => {
|
||||||
|
result_nodes.push(node.clone());
|
||||||
|
}
|
||||||
TypedASTNodeKind::Function(f) => {
|
TypedASTNodeKind::Function(f) => {
|
||||||
// Skip generic functions - they'll be added as specialized versions when needed
|
// Skip generic functions - they'll be added as specialized versions when needed
|
||||||
if !f.parameters.is_empty() {
|
if !f.parameters.is_empty() {
|
||||||
|
|
@ -322,6 +325,7 @@ impl Monomorphizer {
|
||||||
let mut needs = Vec::new();
|
let mut needs = Vec::new();
|
||||||
let new_kind = match &expr.kind {
|
let new_kind = match &expr.kind {
|
||||||
TypedExprKind::Int(_)
|
TypedExprKind::Int(_)
|
||||||
|
| TypedExprKind::TypedInt(_, _)
|
||||||
| TypedExprKind::Float(_)
|
| TypedExprKind::Float(_)
|
||||||
| TypedExprKind::Bool(_)
|
| TypedExprKind::Bool(_)
|
||||||
| TypedExprKind::String(_)
|
| TypedExprKind::String(_)
|
||||||
|
|
@ -342,6 +346,11 @@ impl Monomorphizer {
|
||||||
}
|
}
|
||||||
TypedExprKind::Array(new_elems)
|
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) => {
|
TypedExprKind::Tuple(elems) => {
|
||||||
let mut new_elems = Vec::new();
|
let mut new_elems = Vec::new();
|
||||||
|
|
@ -767,6 +776,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::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) => {
|
TypeAnnot::Ptr(inner) => {
|
||||||
let new_inner = self.substitute_in_type_annot(inner, subst_map)?;
|
let new_inner = self.substitute_in_type_annot(inner, subst_map)?;
|
||||||
Ok(TypeAnnot::Ptr(Box::new(new_inner)))
|
Ok(TypeAnnot::Ptr(Box::new(new_inner)))
|
||||||
|
|
@ -777,11 +790,13 @@ impl Monomorphizer {
|
||||||
fn type_to_type_annot(&self, ty: &Type) -> TypeAnnot {
|
fn type_to_type_annot(&self, ty: &Type) -> TypeAnnot {
|
||||||
match ty {
|
match ty {
|
||||||
Type::Int => TypeAnnot::Var("int".to_string()),
|
Type::Int => TypeAnnot::Var("int".to_string()),
|
||||||
|
Type::U8 => TypeAnnot::Var("u8".to_string()),
|
||||||
Type::Float => TypeAnnot::Var("float".to_string()),
|
Type::Float => TypeAnnot::Var("float".to_string()),
|
||||||
Type::Bool => TypeAnnot::Var("bool".to_string()),
|
Type::Bool => TypeAnnot::Var("bool".to_string()),
|
||||||
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::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::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();
|
||||||
|
|
@ -901,6 +916,9 @@ impl Monomorphizer {
|
||||||
TypeAnnot::Array(inner) => {
|
TypeAnnot::Array(inner) => {
|
||||||
self.collect_needs_from_type(inner, needs);
|
self.collect_needs_from_type(inner, needs);
|
||||||
}
|
}
|
||||||
|
TypeAnnot::FixedArray(inner, _) => {
|
||||||
|
self.collect_needs_from_type(inner, needs);
|
||||||
|
}
|
||||||
TypeAnnot::Ptr(inner) => {
|
TypeAnnot::Ptr(inner) => {
|
||||||
self.collect_needs_from_type(inner, needs);
|
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();
|
let tys = types.iter().map(|t| self.type_annot_to_type(t)).collect();
|
||||||
Type::Tuple(tys)
|
Type::Tuple(tys)
|
||||||
}
|
}
|
||||||
TypeAnnot::Array(inner) => {
|
TypeAnnot::Array(inner) => Type::Array(Box::new(self.type_annot_to_type(inner))),
|
||||||
let inner_type = self.type_annot_to_type(inner);
|
TypeAnnot::FixedArray(inner, size) => Type::FixedArray(Box::new(self.type_annot_to_type(inner)), *size as usize),
|
||||||
Type::Array(Box::new(inner_type))
|
|
||||||
}
|
|
||||||
TypeAnnot::Ptr(inner) => {
|
TypeAnnot::Ptr(inner) => {
|
||||||
let inner_type = self.type_annot_to_type(inner);
|
let inner_type = self.type_annot_to_type(inner);
|
||||||
Type::Ptr(Box::new(inner_type))
|
Type::Ptr(Box::new(inner_type))
|
||||||
|
|
@ -975,6 +991,9 @@ fn check_node_for_typevars(node: &TypedASTNode) -> Result<(), MonomorphizationEr
|
||||||
TypedASTNodeKind::Function(f) => {
|
TypedASTNodeKind::Function(f) => {
|
||||||
check_function_for_typevars(f)?;
|
check_function_for_typevars(f)?;
|
||||||
}
|
}
|
||||||
|
TypedASTNodeKind::Const(c) => {
|
||||||
|
// Consts should not have typevars
|
||||||
|
}
|
||||||
TypedASTNodeKind::Struct(s) => {
|
TypedASTNodeKind::Struct(s) => {
|
||||||
check_struct_for_typevars(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::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::FixedArray(inner, _) => has_typevars_in_type_annot(inner),
|
||||||
TypeAnnot::Ptr(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,
|
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) => {
|
Some(Token::KeywordStruct) => {
|
||||||
self.next();
|
self.next();
|
||||||
let struct_def = self.parse_struct()?;
|
let struct_def = self.parse_struct()?;
|
||||||
|
|
@ -211,12 +221,33 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
let span = self.peek_span().unwrap_or(start..start);
|
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),
|
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> {
|
fn parse_attribute(&mut self) -> Result<Attribute, ParseError> {
|
||||||
self.expect(Token::At)?;
|
self.expect(Token::At)?;
|
||||||
let start = self.peek_span().unwrap_or(0..0).start;
|
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::KeywordInt, _)) => TypeAnnot::Cons("int".to_string(), vec![]),
|
||||||
Some((Token::KeywordFloat, _)) => TypeAnnot::Cons("float".to_string(), vec![]),
|
Some((Token::KeywordFloat, _)) => TypeAnnot::Cons("float".to_string(), vec![]),
|
||||||
Some((Token::KeywordString, _)) => TypeAnnot::Cons("string".to_string(), vec![]),
|
Some((Token::KeywordString, _)) => TypeAnnot::Cons("string".to_string(), vec![]),
|
||||||
|
Some((Token::KeywordU8, _)) => TypeAnnot::Cons("u8".to_string(), vec![]),
|
||||||
Some((Token::LParen, _)) => {
|
Some((Token::LParen, _)) => {
|
||||||
// Check for unit type: ()
|
// Check for unit type: ()
|
||||||
if matches!(self.peek(), Some(Token::RParen)) {
|
if matches!(self.peek(), Some(Token::RParen)) {
|
||||||
|
|
@ -912,8 +944,23 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Some((Token::LBracket, _)) => {
|
Some((Token::LBracket, _)) => {
|
||||||
let inner = self.parse_type_annot()?;
|
let inner = self.parse_type_annot()?;
|
||||||
self.expect(Token::RBracket)?;
|
if matches!(self.peek(), Some(Token::Semicolon)) {
|
||||||
TypeAnnot::Array(Box::new(inner))
|
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((Token::Bang, _)) => TypeAnnot::Cons("never".to_string(), vec![]),
|
||||||
Some((_, span)) => {
|
Some((_, span)) => {
|
||||||
|
|
@ -1157,14 +1204,44 @@ impl Parser {
|
||||||
Ok(left)
|
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()?;
|
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 {
|
loop {
|
||||||
if matches!(self.peek(), Some(Token::BitAnd)) {
|
if matches!(self.peek(), Some(Token::BitAnd)) {
|
||||||
let start = left.span.start;
|
let start = left.span.start;
|
||||||
self.next();
|
self.next();
|
||||||
let right = self.parse_eq_expr()?;
|
let right = self.parse_shift_expr()?;
|
||||||
let end = right.span.end;
|
let end = right.span.end;
|
||||||
left = Expr {
|
left = Expr {
|
||||||
kind: ExprKind::BinOp(Box::new(left), BinOp::BitwiseAnd, Box::new(right)),
|
kind: ExprKind::BinOp(Box::new(left), BinOp::BitwiseAnd, Box::new(right)),
|
||||||
|
|
@ -1450,6 +1527,15 @@ impl Parser {
|
||||||
attributes: Vec::new(),
|
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)) => {
|
Some(Token::Float(f)) => {
|
||||||
self.next();
|
self.next();
|
||||||
let end = self.peek_span().unwrap_or(start..start).end;
|
let end = self.peek_span().unwrap_or(start..start).end;
|
||||||
|
|
@ -1607,25 +1693,44 @@ impl Parser {
|
||||||
}
|
}
|
||||||
Some(Token::LBracket) => {
|
Some(Token::LBracket) => {
|
||||||
self.next();
|
self.next();
|
||||||
let mut elements = Vec::new();
|
let first_expr = self.parse_expr()?;
|
||||||
loop {
|
if matches!(self.peek(), Some(Token::Semicolon)) {
|
||||||
if matches!(self.peek(), Some(Token::RBracket)) {
|
self.next();
|
||||||
self.next();
|
let size = match self.next() {
|
||||||
break;
|
Some((Token::Int(n), _)) => n,
|
||||||
}
|
Some((_, span)) => {
|
||||||
elements.push(self.parse_expr()?);
|
return self.error("Expected integer size for fixed array".to_string(), span);
|
||||||
|
}
|
||||||
if matches!(self.peek(), Some(Token::Comma)) {
|
None => {
|
||||||
self.next();
|
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) => {
|
Some(Token::KeywordLet) => {
|
||||||
self.next();
|
self.next();
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@ use std::fmt;
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Int,
|
Int,
|
||||||
|
U8,
|
||||||
Float,
|
Float,
|
||||||
Bool,
|
Bool,
|
||||||
String,
|
String,
|
||||||
Unit,
|
Unit,
|
||||||
Never,
|
Never,
|
||||||
Array(Box<Type>),
|
Array(Box<Type>),
|
||||||
|
FixedArray(Box<Type>, usize),
|
||||||
Ptr(Box<Type>),
|
Ptr(Box<Type>),
|
||||||
Tuple(Vec<Type>),
|
Tuple(Vec<Type>),
|
||||||
Function(Vec<Type>, Box<Type>),
|
Function(Vec<Type>, Box<Type>),
|
||||||
|
|
@ -26,12 +28,14 @@ impl Type {
|
||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Type::Int => "int".to_string(),
|
Type::Int => "int".to_string(),
|
||||||
|
Type::U8 => "u8".to_string(),
|
||||||
Type::Float => "float".to_string(),
|
Type::Float => "float".to_string(),
|
||||||
Type::Bool => "bool".to_string(),
|
Type::Bool => "bool".to_string(),
|
||||||
Type::String => "string".to_string(),
|
Type::String => "string".to_string(),
|
||||||
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::FixedArray(inner, size) => format!("[{}; {}]", inner.to_string(), size),
|
||||||
Type::Ptr(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();
|
||||||
|
|
@ -366,6 +370,351 @@ impl TypeChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_builtin_functions(&mut self) {
|
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
|
// ODE Physics Engine functions
|
||||||
self.env.functions.insert(
|
self.env.functions.insert(
|
||||||
"ode_init".to_string(),
|
"ode_init".to_string(),
|
||||||
|
|
@ -1560,6 +1909,19 @@ impl TypeChecker {
|
||||||
|
|
||||||
fn typecheck_node(&mut self, node: &ASTNode) -> Result<TypedASTNode, TypeError> {
|
fn typecheck_node(&mut self, node: &ASTNode) -> Result<TypedASTNode, TypeError> {
|
||||||
let ty = match &node.kind {
|
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) => {
|
ASTNodeKind::Function(f) => {
|
||||||
let typed_func = self.typecheck_function(f)?;
|
let typed_func = self.typecheck_function(f)?;
|
||||||
let ty = typed_func.ty.clone();
|
let ty = typed_func.ty.clone();
|
||||||
|
|
@ -1761,6 +2123,16 @@ impl TypeChecker {
|
||||||
fn typecheck_expr(&mut self, expr: &Expr) -> Result<TypedExpr, TypeError> {
|
fn typecheck_expr(&mut self, expr: &Expr) -> Result<TypedExpr, TypeError> {
|
||||||
let (kind, ty) = match &expr.kind {
|
let (kind, ty) = match &expr.kind {
|
||||||
ExprKind::Int(n) => (TypedExprKind::Int(*n), Type::Int),
|
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::Float(f) => (TypedExprKind::Float(*f), Type::Float),
|
||||||
ExprKind::Bool(b) => (TypedExprKind::Bool(*b), Type::Bool),
|
ExprKind::Bool(b) => (TypedExprKind::Bool(*b), Type::Bool),
|
||||||
ExprKind::String(s) => (TypedExprKind::String(s.clone()), Type::String),
|
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) => {
|
ExprKind::Tuple(elements) => {
|
||||||
let mut typed_elements = Vec::new();
|
let mut typed_elements = Vec::new();
|
||||||
let mut types = Vec::new();
|
let mut types = Vec::new();
|
||||||
|
|
@ -1840,7 +2220,7 @@ impl TypeChecker {
|
||||||
let typed_right = self.typecheck_expr(right)?;
|
let typed_right = self.typecheck_expr(right)?;
|
||||||
|
|
||||||
let result_type = match op {
|
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) {
|
if !self.types_compatible(&typed_left.ty, &typed_right.ty) {
|
||||||
return Err(TypeError {
|
return Err(TypeError {
|
||||||
kind: TypeErrorKind::TypeMismatch(
|
kind: TypeErrorKind::TypeMismatch(
|
||||||
|
|
@ -2171,7 +2551,7 @@ impl TypeChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
let element_type = match &typed_array.ty {
|
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 => {
|
ty => {
|
||||||
return Err(TypeError {
|
return Err(TypeError {
|
||||||
kind: TypeErrorKind::NotAnArray(ty.clone()),
|
kind: TypeErrorKind::NotAnArray(ty.clone()),
|
||||||
|
|
@ -2836,13 +3216,14 @@ impl TypeChecker {
|
||||||
TypeInfoKind::Enum(_) => Type::Enum(name.clone(), substituted_args),
|
TypeInfoKind::Enum(_) => Type::Enum(name.clone(), substituted_args),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match name.as_str() {
|
match name.as_str() {
|
||||||
"int" => Type::Int,
|
"int" => Type::Int,
|
||||||
"float" => Type::Float,
|
"u8" => Type::U8,
|
||||||
"bool" => Type::Bool,
|
"float" => Type::Float,
|
||||||
"string" => Type::String,
|
"bool" => Type::Bool,
|
||||||
"unit" => Type::Unit,
|
"string" => Type::String,
|
||||||
"never" => Type::Never,
|
"unit" => Type::Unit,
|
||||||
|
"never" => Type::Never,
|
||||||
_ => Type::Generic(name.clone(), substituted_args),
|
_ => Type::Generic(name.clone(), substituted_args),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2850,6 +3231,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::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::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
|
||||||
|
|
@ -2893,6 +3277,7 @@ impl TypeChecker {
|
||||||
|
|
||||||
match name.as_str() {
|
match name.as_str() {
|
||||||
"int" => Type::Int,
|
"int" => Type::Int,
|
||||||
|
"u8" => Type::U8,
|
||||||
"float" => Type::Float,
|
"float" => Type::Float,
|
||||||
"bool" => Type::Bool,
|
"bool" => Type::Bool,
|
||||||
"string" => Type::String,
|
"string" => Type::String,
|
||||||
|
|
@ -2923,6 +3308,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::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))),
|
TypeAnnot::Ptr(inner) => Type::Ptr(Box::new(self.type_annot_to_type(inner))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2931,12 +3317,14 @@ impl TypeChecker {
|
||||||
match (t1, t2) {
|
match (t1, t2) {
|
||||||
(Type::Unknown, _) | (_, Type::Unknown) => true,
|
(Type::Unknown, _) | (_, Type::Unknown) => true,
|
||||||
(Type::Int, Type::Int) => true,
|
(Type::Int, Type::Int) => true,
|
||||||
|
(Type::U8, Type::U8) => true,
|
||||||
(Type::Float, Type::Float) => true,
|
(Type::Float, Type::Float) => true,
|
||||||
(Type::Bool, Type::Bool) => true,
|
(Type::Bool, Type::Bool) => true,
|
||||||
(Type::String, Type::String) => true,
|
(Type::String, Type::String) => true,
|
||||||
(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::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::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()
|
||||||
|
|
|
||||||
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