Compare commits

..

No commits in common. "6f198b17a98b58375f21c7abfe69945f4ccabdb5" and "22afdb20a4df97a4c5abda6ee1988699b61097d0" have entirely different histories.

12 changed files with 437 additions and 2052 deletions

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -1,549 +0,0 @@
# Suicmez port of game/client.c
# Constants
const PROTOCOL_VERSION = 67
const SERVER_PORT = 27015
const MAX_PLAYERS = 16
const USERNAME_MAX = 16
const TERRAIN_SIZE = 256
const TERRAIN_SCALE = 1.0
const TERRAIN_MIN = - (TERRAIN_SIZE * TERRAIN_SCALE / 2.0)
const TERRAIN_MAX = TERRAIN_SIZE * TERRAIN_SCALE / 2.0
const WEAPON_PISTOL = 0
const WEAPON_RIFLE = 1
const ITEM_NONE = 0
const ITEM_MEDKIT = 1
const ITEM_AMMO_PISTOL = 2
const ITEM_AMMO_RIFLE = 3
const MAX_ITEMS = 64
const BTN_RELOAD = (1 << 0)
const BTN_SWITCH_PISTOL = (1 << 1)
const BTN_SWITCH_RIFLE = (1 << 2)
const BTN_PICK = (1 << 3)
const BTN_USE_MEDKIT = (1 << 4)
const BTN_JUMP = (1 << 5)
# Structs
struct DirectionalLight
direction: suic_vector3
color: suic_vector3
intensity: float
ambient_intensity: float
shadow_bias: float
shadow_intensity: float
end
struct TerrainShader
shader: suic_shader_handle
loc_view_pos: int
loc_light_dir: int
loc_light_color: int
loc_light_intensity: int
loc_ambient_intensity: int
loc_terrain_color: int
end
# Network message types
enum MsgType
MSG_HELLO
MSG_WELCOME
MSG_INPUT
MSG_SNAPSHOT
MSG_SHOOT
MSG_ITEMS
MSG_ROOM_STATE
end
struct MsgHello
type_: u8
protocol: u32
username: string
end
struct MsgWelcome
type_: u8
player_id: u8
server_tick: u32
end
struct MsgInput
type_: u8
player_id: u8
client_tick: u32
move_x: float
move_z: float
yaw: float
pitch: float
buttons: u8
end
struct MsgShoot
type_: u8
player_id: u8
client_tick: u32
end
struct PlayerStateNet
id: u8
alive: u8
hp: i16
x: float
y: float
z: float
yaw: float
pitch: float
weapon: u8
pistol_mag: i16
rifle_mag: i16
pistol_ammo: i16
rifle_ammo: i16
medkits: i16
reload_time_left: i16
username: string
end
struct MsgSnapshot
type_: u8
server_tick: u32
count: u8
p: [PlayerStateNet]
end
struct ItemNet
id: u16
type_: u8
qty: i16
x: float
y: float
z: float
end
struct MsgItems
type_: u8
server_tick: u32
count: u8
items: [ItemNet]
end
struct MsgRoomState
type_: u8
state: u8
countdown_remaining: float
winner_id: u8
winner_name: string
end
struct RemotePlayer
present: int
alive: int
hp: int
pos: suic_vector3
prev_pos: suic_vector3
yaw: float
pitch: float
weapon: u8
pistol_mag: i16
rifle_mag: i16
pistol_ammo: i16
rifle_ammo: i16
medkits: i16
reload_time_left: i16
username: [u8; 16]
end
struct WorldItem
present: int
id: u16
type_: u8
qty: i16
pos: suic_vector3
end
# Main function
fn main() -> int do
let sw = 1280
let sh = 720
suic_init_window(sw, sh, "Voxel Shooter - Client (Suicmez)")
suic_set_target_fps(120)
# Username prompt
let my_name = [0; 16]
suic_username_prompt(my_name)
suic_disable_cursor()
# Generate terrain mesh
let terrain_mesh = suic_generate_terrain_mesh()
let terrain_model = suic_load_model_from_mesh(terrain_mesh)
# Setup directional light
let dir_light = DirectionalLight {
direction: suic_vector3 { x: -0.8, y: -1.0, z: -0.6 },
color: suic_vector3 { x: 1.0, y: 1.0, z: 1.0 },
intensity: 1.2,
ambient_intensity: 0.3,
shadow_bias: 0.005,
shadow_intensity: 0.4
}
let sock = suic_udp_socket_create()
if sock < 0 do
return 1
end
suic_udp_set_nonblocking(sock)
let my_id = 255
let client_tick = 0
let rp = [RemotePlayer { present: 0 }; 16]
let wi = [WorldItem { present: 0 }; 64]
# Room state
let room_state = 0
let countdown_remaining = 0.0
let winner_name = [0; 16]
let cam_pos = suic_vector3 { x: 0, y: 5.0, z: 6 }
let yaw = 0.0
let pitch = 0.0
let prev_body_pos = suic_vector3 { x: 0, y: 5.0, z: 6 }
let current_target_body = suic_vector3 { x: 0, y: 5.0, z: 6 }
let interp_timer = 0.0
let recoil_yaw = 0.0
let recoil_pitch = 0.0
let cross_spread = 0.0
let scoped = 0
let fire_cooldown = 0.0
let shots_in_burst = 0
let burst_reset_timer = 0.0
let pistol_fire_rate = 4.0
let rifle_fire_rate = 12.0
let recoil_return = 18.0
let cross_return = 14.0
let pistol_kick_pitch = 0.010
let pistol_kick_yaw = 0.004
let rifle_kick_pitch = 0.018
let rifle_kick_yaw = 0.010
let pistol_cross_kick = 2.0
let rifle_cross_kick = 4.0
let pistol_spray_grow = 0.4
let rifle_spray_grow = 1.2
let burst_reset_time = 0.18
let hello_buf = [0; 21] # sizeof(MsgHello)
suic_msg_hello_pack(hello_buf, MSG_HELLO, PROTOCOL_VERSION, my_name)
suic_udp_sendto(sock, hello_buf, 21, "127.0.0.1", SERVER_PORT)
while not suic_window_should_close() do
client_tick = client_tick + 1
let dt = suic_get_frame_time()
fire_cooldown = fire_cooldown - dt
if fire_cooldown < 0.0 do fire_cooldown = 0.0 end
burst_reset_timer = burst_reset_timer - dt
if burst_reset_timer <= 0.0 do shots_in_burst = 0 end
let k = 1.0 - suic_expf(-recoil_return * dt)
recoil_yaw = recoil_yaw + (0.0 - recoil_yaw) * k
recoil_pitch = recoil_pitch + (0.0 - recoil_pitch) * k
k = 1.0 - suic_expf(-cross_return * dt)
cross_spread = cross_spread + (0.0 - cross_spread) * k
if cross_spread < 0.01 do cross_spread = 0.0 end
# Network receive
let buf = [0; 1400]
let from_host = [0; 256]
let from_port = 0
let n = suic_udp_recvfrom(sock, buf, 1400, from_host, from_port)
if n > 0 do
let type_ = buf[0]
if type_ == MSG_WELCOME do
my_id = suic_msg_welcome_unpack(buf)
end else if type_ == MSG_SNAPSHOT do
suic_msg_snapshot_unpack(buf, rp, 16)
if my_id != 255 and rp[my_id].present do
prev_body_pos = current_target_body
current_target_body = rp[my_id].pos
interp_timer = 0.0
end
end else if type_ == MSG_ITEMS do
suic_msg_items_unpack(buf, wi, 64)
end else if type_ == MSG_ROOM_STATE do
suic_msg_room_state_unpack(buf, &room_state, &countdown_remaining, winner_name)
end
end
# Interpolate camera position
if my_id != 255 and rp[my_id].present do
let interp_factor = interp_timer / (1.0 / 20.0)
if interp_factor > 1.0 do interp_factor = 1.0 end
let interp_body = suic_vector3 {
x: prev_body_pos.x * (1.0 - interp_factor) + current_target_body.x * interp_factor,
y: prev_body_pos.y * (1.0 - interp_factor) + current_target_body.y * interp_factor,
z: prev_body_pos.z * (1.0 - interp_factor) + current_target_body.z * interp_factor
}
cam_pos.x = interp_body.x
cam_pos.y = interp_body.y + 1.0
cam_pos.z = interp_body.z + 0.0001
# Prevent camera from clipping into terrain
let terrain_h = suic_get_terrain_height(cam_pos.x, cam_pos.z)
cam_pos.y = suic_fmaxf(cam_pos.y, terrain_h + 1.5)
end
interp_timer = interp_timer + dt
let md = suic_get_mouse_delta()
let sens = 0.0025
yaw = yaw - md.x * sens
pitch = pitch - md.y * sens
if pitch < -1.5 do pitch = -1.5 end
if pitch > 1.5 do pitch = 1.5 end
let view_yaw = yaw + recoil_yaw
let view_pitch = pitch + recoil_pitch
if view_pitch < -1.5 do view_pitch = -1.5 end
if view_pitch > 1.5 do view_pitch = 1.5 end
let move_x = 0.0
let move_z = 0.0
if suic_is_key_down(KEY_W) do move_z = move_z + 1.0 end
if suic_is_key_down(KEY_A) do move_x = move_x + 1.0 end
if suic_is_key_down(KEY_S) do move_z = move_z - 1.0 end
if suic_is_key_down(KEY_D) do move_x = move_x - 1.0 end
let buttons = 0
if suic_is_key_pressed(KEY_ONE) do buttons = buttons bitor BTN_SWITCH_PISTOL end
if suic_is_key_pressed(KEY_TWO) do buttons = buttons bitor BTN_SWITCH_RIFLE end
if suic_is_key_pressed(KEY_R) do buttons = buttons bitor BTN_RELOAD end
if suic_is_key_pressed(KEY_F) do buttons = buttons bitor BTN_PICK end
if suic_is_key_pressed(KEY_H) do buttons = buttons bitor BTN_USE_MEDKIT end
if suic_is_key_pressed(KEY_SPACE) do buttons = buttons bitor BTN_JUMP end
if suic_is_key_pressed(KEY_Z) do scoped = not scoped end
if my_id != 255 do
let in_buf = [0; 23] # sizeof(MsgInput)
suic_msg_input_pack(in_buf, MSG_INPUT, my_id, client_tick, move_x, move_z, view_yaw, view_pitch, buttons as u8)
suic_udp_sendto(sock, in_buf, 23, "127.0.0.1", SERVER_PORT)
end
if my_id != 255 and suic_is_mouse_button_down(MOUSE_BUTTON_LEFT) and fire_cooldown <= 0.0 and rp[my_id].present do
let wpn = rp[my_id].weapon
let rate = rifle_fire_rate
if wpn == WEAPON_PISTOL do rate = pistol_fire_rate end
fire_cooldown = 1.0 / rate
shots_in_burst = shots_in_burst + 1
burst_reset_timer = burst_reset_time
if wpn == WEAPON_PISTOL do
recoil_pitch = recoil_pitch + pistol_kick_pitch
recoil_yaw = recoil_yaw + (suic_get_random_value(-1000, 1000) as float / 1000.0) * pistol_kick_yaw
cross_spread = cross_spread + pistol_cross_kick + shots_in_burst as float * pistol_spray_grow
end else do
recoil_pitch = recoil_pitch + rifle_kick_pitch
recoil_yaw = recoil_yaw + (suic_get_random_value(-1000, 1000) as float / 1000.0) * rifle_kick_yaw
cross_spread = cross_spread + rifle_cross_kick + shots_in_burst as float * rifle_spray_grow
end
let sh_buf = [0; 6] # sizeof(MsgShoot)
suic_msg_shoot_pack(sh_buf, MSG_SHOOT, my_id, client_tick)
suic_udp_sendto(sock, sh_buf, 6, "127.0.0.1", SERVER_PORT)
end
let forward = suic_vector3 {
x: suic_sinf(view_yaw) * suic_cosf(view_pitch),
y: suic_sinf(view_pitch),
z: suic_cosf(view_yaw) * suic_cosf(view_pitch)
}
# Offset camera position: 0.3m in front, 0.2m below
cam_pos = suic_vector3 {
x: cam_pos.x + forward.x * 0.3,
y: cam_pos.y + forward.y * 0.3 - 0.2,
z: cam_pos.z + forward.z * 0.3
}
# Ensure camera doesn't clip into terrain after offset
let terrain_h = suic_get_terrain_height(cam_pos.x, cam_pos.z)
cam_pos.y = suic_fmaxf(cam_pos.y, terrain_h + 1.5)
suic_begin_drawing()
suic_clear_background(135, 206, 235, 255) # Sky blue
let fovy = 75.0
if scoped do fovy = 30.0 end
suic_begin_mode3d(cam_pos.x, cam_pos.y, cam_pos.z, forward.x, forward.y, forward.z, suic_vector3 { x: 0, y: 1, z: 0 }, fovy, 0)
# Draw terrain
suic_draw_model(terrain_model, 0, 0, 0, 1.0, 1.0, 1.0, 80, 140, 70, 255)
# Draw border
suic_draw_cube(0, 0, 0, 256.0, 1000.0, 256.0, 255, 0, 0, 100)
# Items
let i = 0
while i < 64 do
if wi[i].present do
let ic = suic_color { r: 220, g: 220, b: 220, a: 255 }
if wi[i].type_ == ITEM_MEDKIT do
ic = suic_color { r: 120, g: 255, b: 120, a: 255 }
end else do
if wi[i].type_ == ITEM_AMMO_PISTOL do
ic = suic_color { r: 255, g: 220, b: 120, a: 255 }
end else do
if wi[i].type_ == ITEM_AMMO_RIFLE do
ic = suic_color { r: 255, g: 180, b: 120, a: 255 }
end
end
end
# Apply basic lighting
let item_normal = suic_vector3 { x: 0, y: 1, z: 0 }
let lit_color = suic_apply_lighting_with_shadows(ic, item_normal, wi[i].pos, dir_light.direction, dir_light.intensity, dir_light.ambient_intensity, dir_light.shadow_bias)
suic_draw_sphere(wi[i].pos.x, wi[i].pos.y, wi[i].pos.z, 0.3, lit_color.r, lit_color.g, lit_color.b, lit_color.a)
end
i = i + 1
end
# Players
let i = 0
while i < 16 do
if rp[i].present do
let interp_factor = interp_timer / (1.0 / 20.0)
if interp_factor > 1.0 do interp_factor = 1.0 end
let p = suic_vector3 {
x: rp[i].prev_pos.x * (1.0 - interp_factor) + rp[i].pos.x * interp_factor,
y: rp[i].prev_pos.y * (1.0 - interp_factor) + rp[i].pos.y * interp_factor,
z: rp[i].prev_pos.z * (1.0 - interp_factor) + rp[i].pos.z * interp_factor
}
let c = suic_color { r: 255, g: 80, b: 80, a: 255 }
if i == my_id do
c = suic_color { r: 80, g: 180, b: 255, a: 255 }
end
if not rp[i].alive do
c = suic_color { r: 120, g: 120, b: 120, a: 255 }
end
# Apply basic lighting
let player_normal = suic_vector3 { x: 0, y: 1, z: 0 }
let lit_player_color = suic_apply_lighting_with_shadows(c, player_normal, p, dir_light.direction, dir_light.intensity, dir_light.ambient_intensity, dir_light.shadow_bias)
suic_draw_capsule(p.x, p.y - 0.5, p.z, p.x, p.y + 0.5, p.z, 0.35, 8, 8, lit_player_color.r, lit_player_color.g, lit_player_color.b, lit_player_color.a)
end
i = i + 1
end
suic_end_mode3d()
# Nameplates - removed for debugging
# HUD
if my_id == 255 or not rp[my_id].present do
suic_draw_text("Connecting...", 10, 10, 20, 255, 255, 255, 255)
end
if my_id != 255 and rp[my_id].present do
suic_draw_rectangle(10, 10, 280, 110, 0, 0, 0, 120)
suic_draw_text("HP", 20, 20, 20, 255, 255, 255, 255)
let health_bar_width = (rp[my_id].hp * 220) / 100
let health_color = suic_color { r: 255, g: 80, b: 80, a: 120 }
if rp[my_id].hp > 60 do
health_color = suic_color { r: 80, g: 255, b: 80, a: 120 }
end else do
if rp[my_id].hp > 30 do
health_color = suic_color { r: 255, g: 200, b: 80, a: 120 }
end
end
suic_draw_rectangle(20, 45, 220, 20, 40, 40, 40, 255)
suic_draw_rectangle(20, 45, health_bar_width, 20, health_color.r, health_color.g, health_color.b, health_color.a)
suic_draw_text(suic_text_format("%d", rp[my_id].hp), 250, 47, 18, 255, 255, 255, 255)
let medkit_color_r = 120
let medkit_color_g = 120
let medkit_color_b = 120
if rp[my_id].medkits > 0 do
medkit_color_g = 255
medkit_color_b = 120
end
suic_draw_text(suic_text_format("Medkits: %d (H to use)", rp[my_id].medkits), 20, 75, 18, 120, medkit_color_g, medkit_color_b, 120)
suic_draw_text("1=Pistol 2=Rifle R=Reload F=Pick SPACE=Jump", 20, 95, 12, 150, 150, 150, 150)
let weapon_name = "RIFLE"
let weapon_color = suic_color { r: 255, g: 150, b: 100, a: 255 }
let current_mag = rp[my_id].rifle_mag
let reserve_ammo = rp[my_id].rifle_ammo
if rp[my_id].weapon == WEAPON_PISTOL do
weapon_name = "PISTOL"
weapon_color = suic_color { r: 100, g: 200, b: 255, a: 255 }
current_mag = rp[my_id].pistol_mag
reserve_ammo = rp[my_id].pistol_ammo
end
suic_draw_rectangle(sw - 260, sh - 120, 250, 110, 0, 0, 0, 180)
suic_draw_text(weapon_name, sw - 250, sh - 110, 28, weapon_color.r, weapon_color.g, weapon_color.b, weapon_color.a)
suic_draw_text(suic_text_format("%d", current_mag), sw - 250, sh - 75, 40, 255, 255, 255, 255)
suic_draw_text(suic_text_format("/ %d", reserve_ammo), sw - 140, sh - 65, 24, 180, 180, 180, 255)
if rp[my_id].reload_time_left > 0 do
suic_draw_text("RELOADING...", sw - 250, sh - 30, 20, 255, 200, 80, 255)
end else if current_mag == 0 do
suic_draw_text("RELOAD!", sw - 250, sh - 30, 20, 255, 80, 80, 255)
end
end
suic_draw_fps(sw - 90, 10)
# Room state overlay
if room_state == 0 do # Waiting
suic_draw_rectangle(sw / 2 - 150, sh / 2 - 50, 350, 100, 0, 0, 0, 200)
suic_draw_text("WAITING FOR PLAYERS", sw / 2 - 120, sh / 2 - 30, 24, 255, 255, 255, 255)
suic_draw_text("Need at least 2 players", sw / 2 - 100, sh / 2 - 5, 18, 200, 200, 200, 255)
end
if room_state == 1 do # Counting down
suic_draw_rectangle(sw / 2 - 150, sh / 2 - 50, 350, 100, 0, 0, 0, 200)
suic_draw_text("GAME STARTING SOON", sw / 2 - 120, sh / 2 - 30, 24, 255, 255, 80, 255)
suic_draw_text(suic_text_format("%.1f seconds", countdown_remaining), sw / 2 - 60, sh / 2 - 5, 20, 255, 255, 255, 255)
end
if room_state == 3 do # Finished
suic_draw_rectangle(sw / 2 - 200, sh / 2 - 50, 450, 100, 0, 0, 0, 200)
suic_draw_text("GAME FINISHED", sw / 2 - 80, sh / 2 - 30, 28, 255, 80, 80, 255)
if winner_name[0] do
suic_draw_text(suic_text_format("Winner: %s", winner_name), sw / 2 - 100, sh / 2 - 5, 24, 255, 255, 80, 255)
end
if not winner_name[0] do
suic_draw_text("No winner", sw / 2 - 50, sh / 2 - 5, 24, 255, 255, 255, 255)
end
end
# Crosshair
let cx = sw / 2
let cy = sh / 2
let gap = 6 + cross_spread as int
let len = 10
let radius = 3.0
if scoped do
gap = 2
len = 5
radius = 1.5
end
let thick = 2
let col = suic_color { r: 240, g: 240, b: 245, a: 220 }
suic_draw_line(cx - gap - len, cy - thick / 2, cx - gap, cy - thick / 2, col.r, col.g, col.b, col.a)
suic_draw_line(cx + gap, cy - thick / 2, cx + gap + len, cy - thick / 2, col.r, col.g, col.b, col.a)
suic_draw_line(cx - thick / 2, cy - gap - len, cx - thick / 2, cy - gap, col.r, col.g, col.b, col.a)
suic_draw_line(cx - thick / 2, cy + gap, cx - thick / 2, cy + gap + len, col.r, col.g, col.b, col.a)
suic_draw_circle(cx, cy, radius, 240, 240, 245, 160)
suic_end_drawing()
end
suic_unload_model(terrain_model)
suic_unload_mesh(terrain_mesh)
suic_close_window()
suic_udp_socket_close(sock)
0
end

View file

@ -337,10 +337,6 @@ impl Transpiler {
}
fn generate_struct_decl(&self, struct_decl: &CStructDecl) -> String {
// Skip predefined structs that are already declared in included headers
if matches!(struct_decl.name.as_str(), "Shader" | "Color") {
return String::new();
}
let mut output = format!("struct {} {{\n", struct_decl.name);
for field in &struct_decl.fields {
output.push_str(&format!(" {} {};\n", field.ty.to_string(), field.name));
@ -350,10 +346,6 @@ impl Transpiler {
}
fn generate_typeinfo_decl(&self, struct_decl: &CStructDecl) -> String {
// Skip predefined structs
if matches!(struct_decl.name.as_str(), "Shader" | "Color") {
return String::new();
}
if let Some(bitmap) = self.typeinfo_map.get(&struct_decl.name) {
// Generate pointer bitmap as a C array
let bitmap_str = bitmap
@ -804,7 +796,7 @@ impl Transpiler {
"Vec3" => "suic_vec3".to_string(),
_ => format!("struct {}", struct_name),
};
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

View file

@ -81,8 +81,6 @@ struct ParsedFile {
nodes: Vec<ASTNode>,
/// Hash of the file content at parse time
content_hash: u64,
/// Whether this file is in unsafe mode
is_unsafe: bool,
}
/// Tracks global symbols and their definitions
@ -126,8 +124,6 @@ pub struct ImportResolver {
processing_stack: HashSet<String>,
/// Dependency graph: file -> list of files it depends on
dependency_graph: HashMap<String, HashSet<String>>,
/// Whether any file in the current compilation is unsafe
has_unsafe_files: bool,
}
impl ImportResolver {
@ -137,7 +133,6 @@ impl ImportResolver {
symbol_registry: GlobalSymbolRegistry::default(),
processing_stack: HashSet::new(),
dependency_graph: HashMap::new(),
has_unsafe_files: false,
}
}
@ -196,7 +191,6 @@ impl ImportResolver {
})?;
let content_hash = Self::hash_content(&source);
let is_unsafe = source.trim_start().starts_with("# UNSAFE");
// Check if we have a valid cached version
if let Some(cached) = self.parse_cache.get(filename) {
@ -217,7 +211,6 @@ impl ImportResolver {
ParsedFile {
nodes: nodes.clone(),
content_hash,
is_unsafe,
},
);
@ -302,13 +295,6 @@ impl ImportResolver {
let nodes = self.parse_file(filename)?;
let mut result = Vec::new();
// Check if this file is unsafe
if let Some(cached) = self.parse_cache.get(filename) {
if cached.is_unsafe {
self.has_unsafe_files = true;
}
}
// Collect dependencies
let deps = self.collect_dependencies(filename, &nodes);
self.dependency_graph
@ -407,23 +393,10 @@ impl ImportResolver {
Ok(result)
}
/// Check if the current compilation contains any unsafe files
pub fn has_unsafe_files(&self) -> bool {
self.has_unsafe_files
}
/// Resolve all imports starting from the given file
pub fn resolve(&mut self, filename: &str) -> Result<Vec<ASTNode>, ImportError> {
println!("Starting import resolution...");
self.has_unsafe_files = false; // Reset for new compilation
let result = self.resolve_imports_recursive(filename);
// Check if the main file is unsafe
if let Ok(source) = fs::read_to_string(filename) {
if source.trim_start().starts_with("# UNSAFE") {
self.has_unsafe_files = true;
}
}
result
self.resolve_imports_recursive(filename)
}
}

View file

@ -1,103 +1,13 @@
use clap::Parser;
use std::fs;
use suicmez::{
ast::*,
codegen::transpiler::Transpiler,
import_resolver::ImportResolver,
lambda_lower::LambdaLowerer,
monomorphize::{Monomorphizer, check_no_typevars},
typechecker::{Type, TypeChecker},
typechecker::TypeChecker,
};
/// Convert ASTNode to TypedASTNode for unsafe mode (with dummy types)
fn convert_to_typed_ast(nodes: &[ASTNode]) -> Vec<TypedASTNode> {
nodes.iter().map(|node| {
let dummy_type = Type::Unit; // Use unit type as dummy
let dummy_expr = TypedExpr {
kind: TypedExprKind::Int(0), // dummy expression
span: Span::new(&(0..0), "dummy".to_string()),
attributes: vec![],
ty: dummy_type.clone(),
};
let kind = match &node.kind {
ASTNodeKind::Function(f) => TypedASTNodeKind::Function(TypedFunction {
name: f.name.clone(),
parameters: f.parameters.clone(),
args: f.args.iter().map(|(name, typ)| {
(BindingId(0), name.clone(), typ.clone()) // dummy binding id
}).collect(),
return_type: f.return_type.clone(),
body: dummy_expr.clone(),
ty: dummy_type.clone(),
}),
ASTNodeKind::Const(c) => TypedASTNodeKind::Const(TypedConst {
name: c.name.clone(),
typ: c.typ.clone(),
value: dummy_expr.clone(),
}),
ASTNodeKind::Struct(s) => TypedASTNodeKind::Struct(TypedStruct {
name: s.name.clone(),
parameters: s.parameters.clone(),
fields: s.fields.iter().map(|f| TypedField {
name: f.name.clone(),
field_type: f.field_type.clone(),
span: f.span.clone(),
}).collect(),
}),
ASTNodeKind::Enum(e) => TypedASTNodeKind::Enum(TypedEnum {
name: e.name.clone(),
parameters: e.parameters.clone(),
variants: e.variants.iter().map(|v| TypedVariant {
name: v.name.clone(),
fields: v.fields.clone(),
span: v.span.clone(),
}).collect(),
}),
ASTNodeKind::Impl(i) => TypedASTNodeKind::Impl(TypedImpl {
target: i.target.clone(),
trait_name: i.trait_name.clone(),
methods: i.methods.iter().map(|m| TypedFunction {
name: m.name.clone(),
parameters: m.parameters.clone(),
args: m.args.iter().map(|(name, typ)| {
(BindingId(0), name.clone(), typ.clone())
}).collect(),
return_type: m.return_type.clone(),
body: dummy_expr.clone(),
ty: dummy_type.clone(),
}).collect(),
}),
ASTNodeKind::Trait(t) => TypedASTNodeKind::Trait(TypedTrait {
name: t.name.clone(),
methods: t.methods.clone(),
parameters: t.parameters.clone(),
associated_types: vec![],
}),
ASTNodeKind::Extern(e) => TypedASTNodeKind::Extern(TypedExtern {
name: e.name.clone(),
args: e.args.clone(),
return_type: e.return_type.clone(),
from: e.from.clone(),
span: e.span.clone(),
}),
ASTNodeKind::Load(l) => TypedASTNodeKind::Load(TypedLoad {
library: l.library.clone(),
alias: l.alias.clone(),
span: l.span.clone(),
}),
ASTNodeKind::Use(u) => TypedASTNodeKind::Use(u.clone()),
};
TypedASTNode {
kind,
span: node.span.clone(),
attributes: node.attributes.clone(),
ty: dummy_type,
}
}).collect()
}
#[derive(Parser)]
#[command(author, version, about = "A compiler for the Sui language")]
struct Args {
@ -296,8 +206,6 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> {
}
})?;
let is_unsafe = resolver.has_unsafe_files();
println!(
"Import resolution complete! {} total nodes loaded",
ast_nodes.len()
@ -318,126 +226,59 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> {
lowered_nodes.len()
);
let typed_nodes = if is_unsafe {
println!("Unsafe mode detected - skipping type checking");
// Convert AST nodes to typed nodes with dummy types
convert_to_typed_ast(&lowered_nodes)
} else {
// Typecheck the AST
let mut typechecker = TypeChecker::new();
typechecker
.typecheck_program(&lowered_nodes)
.map_err(|e| format_type_error(&source, &e))?
};
// Typecheck the AST
let mut typechecker = TypeChecker::new();
let typed_nodes = typechecker
.typecheck_program(&lowered_nodes)
.map_err(|e| format_type_error(&source, &e))?;
if is_unsafe {
println!("Unsafe mode - skipping monomorphization and type variable checks");
} else {
println!(
"Type checking passed! {} nodes typechecked.",
typed_nodes.len()
);
println!(
"Type checking passed! {} nodes typechecked.",
typed_nodes.len()
);
// Debug: show typed nodes
println!("\nTyped AST nodes before monomorphization:");
for (i, node) in typed_nodes.iter().enumerate() {
let node_type = match &node.kind {
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())
}
suicmez::ast::TypedASTNodeKind::Enum(e) => {
format!("Enum({}) with {} params", e.name, e.parameters.len())
}
suicmez::ast::TypedASTNodeKind::Impl(imp) => {
format!("Impl({})", imp.target)
}
suicmez::ast::TypedASTNodeKind::Trait(t) => {
format!("Trait({})", t.name)
}
suicmez::ast::TypedASTNodeKind::Extern(e) => {
format!("Extern({})", e.name)
}
suicmez::ast::TypedASTNodeKind::Load(l) => {
format!("Load({})", l.alias)
}
suicmez::ast::TypedASTNodeKind::Use(u) => {
format!("Use({})", u.path)
}
};
println!(" [{}] {}", i, node_type);
}
// Debug: show typed nodes
println!("\nTyped AST nodes before monomorphization:");
for (i, node) in typed_nodes.iter().enumerate() {
let node_type = match &node.kind {
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())
}
suicmez::ast::TypedASTNodeKind::Enum(e) => {
format!("Enum({}) with {} params", e.name, e.parameters.len())
}
suicmez::ast::TypedASTNodeKind::Impl(imp) => {
format!("Impl({})", imp.target)
}
suicmez::ast::TypedASTNodeKind::Trait(t) => {
format!("Trait({})", t.name)
}
suicmez::ast::TypedASTNodeKind::Extern(e) => {
format!("Extern({})", e.name)
}
suicmez::ast::TypedASTNodeKind::Load(l) => {
format!("Load({})", l.alias)
}
suicmez::ast::TypedASTNodeKind::Use(u) => {
format!("Use({})", u.path)
}
};
println!(" [{}] {}", i, node_type);
}
let final_nodes = if is_unsafe {
// Skip monomorphization for unsafe mode
typed_nodes
} else {
// Monomorphize the AST
let monomorphizer = Monomorphizer::new();
let mono_nodes = monomorphizer
.monomorphize_program(&typed_nodes)
.map_err(|e| {
format!(
"Monomorphization error: {}{}",
e.message,
if let Some(span) = &e.span {
format!(" at {}:{}", span.file, span.start)
} else {
String::new()
}
)
})?;
println!(
"Monomorphization passed! {} nodes after specialization.",
mono_nodes.len()
);
// Print detailed info about each node
println!("\nMonomorphized AST nodes:");
for (i, node) in mono_nodes.iter().enumerate() {
let node_type = match &node.kind {
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())
}
suicmez::ast::TypedASTNodeKind::Enum(e) => {
format!("Enum({}) with {} params", e.name, e.parameters.len())
}
suicmez::ast::TypedASTNodeKind::Impl(imp) => {
format!("Impl({})", imp.target)
}
suicmez::ast::TypedASTNodeKind::Trait(t) => {
format!("Trait({})", t.name)
}
suicmez::ast::TypedASTNodeKind::Extern(e) => {
format!("Extern({})", e.name)
}
suicmez::ast::TypedASTNodeKind::Load(l) => {
format!("Load({})", l.alias)
}
suicmez::ast::TypedASTNodeKind::Use(u) => {
format!("Use({})", u.path)
}
};
println!(" [{}] {}", i, node_type);
}
// Check that no type variables remain
check_no_typevars(&mono_nodes).map_err(|e| {
// Monomorphize the AST
let monomorphizer = Monomorphizer::new();
let mono_nodes = monomorphizer
.monomorphize_program(&typed_nodes)
.map_err(|e| {
format!(
"Type variable check failed: {}{}",
"Monomorphization error: {}{}",
e.message,
if let Some(span) = &e.span {
format!(" at {}:{}", span.file, span.start)
@ -447,15 +288,65 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> {
)
})?;
println!("Type variable check passed! No type variables remain in AST.");
println!(
"Monomorphization passed! {} nodes after specialization.",
mono_nodes.len()
);
mono_nodes
};
// Print detailed info about each node
println!("\nMonomorphized AST nodes:");
for (i, node) in mono_nodes.iter().enumerate() {
let node_type = match &node.kind {
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())
}
suicmez::ast::TypedASTNodeKind::Enum(e) => {
format!("Enum({}) with {} params", e.name, e.parameters.len())
}
suicmez::ast::TypedASTNodeKind::Impl(imp) => {
format!("Impl({})", imp.target)
}
suicmez::ast::TypedASTNodeKind::Trait(t) => {
format!("Trait({})", t.name)
}
suicmez::ast::TypedASTNodeKind::Extern(e) => {
format!("Extern({})", e.name)
}
suicmez::ast::TypedASTNodeKind::Load(l) => {
format!("Load({})", l.alias)
}
suicmez::ast::TypedASTNodeKind::Use(u) => {
format!("Use({})", u.path)
}
};
println!(" [{}] {}", i, node_type);
}
// Check that no type variables remain
check_no_typevars(&mono_nodes).map_err(|e| {
format!(
"Type variable check failed: {}{}",
e.message,
if let Some(span) = &e.span {
format!(" at {}:{}", span.file, span.start)
} else {
String::new()
}
)
})?;
println!("Type variable check passed! No type variables remain in AST.");
// Generate C code
let mut transpiler = Transpiler::new(debug);
let c_code = transpiler
.transpile_program(&final_nodes)
.transpile_program(&mono_nodes)
.map_err(|e| format!("Code generation error: {}", e))?;
// Write C code to file

View file

@ -23,28 +23,7 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat
}
struct Color {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct Shader {
int id;
};
static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 };
static const TypeInfo sui_typeinfo_Color = {
.field_count = 4,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_Color
};
static const uint8_t sui_bitmap_Shader[] = { 0 };
static const TypeInfo sui_typeinfo_Shader = {
.field_count = 1,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_Shader
};
int suic_main(void);

View file

@ -23,28 +23,7 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat
}
struct Color {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct Shader {
int id;
};
static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 };
static const TypeInfo sui_typeinfo_Color = {
.field_count = 4,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_Color
};
static const uint8_t sui_bitmap_Shader[] = { 0 };
static const TypeInfo sui_typeinfo_Shader = {
.field_count = 1,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_Shader
};
int suic_main(void);

View file

@ -1,4 +1,4 @@
#include "libsuicmez/libsuicmez.h"
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
@ -23,38 +23,13 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat
}
struct Color {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct Shader {
int id;
};
static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 };
static const TypeInfo sui_typeinfo_Color = {
.field_count = 4,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_Color
};
static const uint8_t sui_bitmap_Shader[] = { 0 };
static const TypeInfo sui_typeinfo_Shader = {
.field_count = 1,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_Shader
};
int suic_main(void);
int suic_main(void) {
if (true) {
1;
} else {
0;
}
(true ? 1 : 0);
int i = 0;
while ((i < 5)) {
i = (i + 1);

View file

@ -1,4 +1,4 @@
#include "libsuicmez/libsuicmez.h"
#include "../libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
@ -23,28 +23,7 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat
}
struct Color {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct Shader {
int id;
};
static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 };
static const TypeInfo sui_typeinfo_Color = {
.field_count = 4,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_Color
};
static const uint8_t sui_bitmap_Shader[] = { 0 };
static const TypeInfo sui_typeinfo_Shader = {
.field_count = 1,
.pointer_count = 0,
.pointer_bitmap = sui_bitmap_Shader
};
int add(int x, int y);
int suic_main(void);

View file

@ -31,8 +31,6 @@ struct Person {
char* name;
int age;
};
;
;
static const uint8_t sui_bitmap_Point[] = { 0, 0 };
static const TypeInfo sui_typeinfo_Point = {
@ -47,14 +45,12 @@ static const TypeInfo sui_typeinfo_Person = {
.pointer_bitmap = sui_bitmap_Person
};
int suic_main(void);
int suic_main(void) {
struct Point* p = suic_alloc_struct(&sui_typeinfo_Point, sizeof(struct Point), &((struct Point){ .x = 5, .y = 10 }));
struct Person* person = suic_alloc_struct(&sui_typeinfo_Person, sizeof(struct Person), &((struct Person){ .name = suic_alloc_array(NULL, sizeof(char), 6, "Alice"), .age = 30 }));
struct Point* p = suic_alloc_struct(&sui_typeinfo_Point, sizeof(struct Point), &(struct Point){ .x = 5, .y = 10 });
struct Person* person = suic_alloc_struct(&sui_typeinfo_Person, sizeof(struct Person), &(struct Person){ .name = suic_alloc_array(NULL, sizeof(char), 6, "Alice"), .age = 30 });
int _ = ((*p).x + (*person).age);
return 0;
}

Binary file not shown.