diff --git a/Cargo.lock b/Cargo.lock index 80d0925..23d1a7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,12 +153,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - [[package]] name = "logos" version = "0.16.0" @@ -267,7 +261,6 @@ version = "0.1.0" dependencies = [ "clap", "indexmap", - "log", "logos", ] diff --git a/Cargo.toml b/Cargo.toml index c7707d2..8d7329a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,4 @@ edition = "2024" [dependencies] clap = { version = "4.5.53", features = ["derive"] } indexmap = "2.0" -log = "0.4.29" logos = "0.16.0" diff --git a/GAMEDEV_GUIDE.md b/GAMEDEV_GUIDE.md deleted file mode 100644 index e47a63a..0000000 --- a/GAMEDEV_GUIDE.md +++ /dev/null @@ -1,287 +0,0 @@ -# Sui Language Game Development Guide - -## Overview - -Sui now has integrated support for game development with **Raylib** (graphics) and **ODE** (physics). This guide explains how to build games with physics simulation and rendering. - -## Key Concepts - -### 1. Physics Engine (ODE) - -ODE (Open Dynamics Engine) provides rigid body dynamics, collision detection, and constraint solving. The key components are: - -- **World**: The container for all physical objects and gravity -- **Bodies**: Dynamic rigid bodies with mass, velocity, and position -- **Geometries**: Collision shapes (boxes, planes, spheres, etc.) -- **Space**: Collision detection space that organizes geometries -- **Contacts**: Joint constraints created when objects collide - -### 2. Graphics Engine (Raylib) - -Raylib provides 2D and 3D graphics, input handling, and audio support. - -### 3. Integration Pattern - -The key to proper physics is the **collision detection loop**: - -```sui -# Initialize -ode_init() -ode_space_collide(world, space, contactgroup) -ode_world_step(world, timestep) -ode_joint_group_empty(contactgroup) -``` - -**Important**: You must call collision detection **before** world step, and clear the contact group **after** the step. - -## Step-by-Step Tutorial - -### Step 1: Initialize the World - -```sui -fn main() -> int do - # Initialize graphics - init_window(800, 600, "My Game") - set_target_fps(60) - - # Initialize physics - ode_init() - let world = ode_world_create() - let space = ode_simple_space_create(0 as *()) - let contactgroup = ode_joint_group_create(0) - - # Set gravity (9.81 m/s² downward) - ode_world_set_gravity(world, 0.0, -9.81, 0.0) - - # ... rest of code -end -``` - -### Step 2: Create Physics Objects - -Each dynamic object needs: -1. A **body** - represents mass and motion -2. A **geometry** - collision shape -3. Mass configuration - -```sui -# Create a cube that falls -let body = ode_body_create(world) -ode_body_set_position(body, 0.0, 5.0, 0.0) # x, y, z -ode_body_set_box_mass(body, 1.0, 1.0, 1.0, 1.0) # density, width, height, length - -# Create collision geometry -let geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) -ode_geom_set_body(geom, body) -``` - -### Step 3: Create Static Objects (Ground) - -Static objects are created without a body - they use infinite mass: - -```sui -# Create a ground plane at y = 0 -let ground_geom = ode_create_plane_geom(space, 0.0, 1.0, 0.0, 0.0) -# Parameters: space, normal_x, normal_y, normal_z, distance_d -``` - -### Step 4: Main Game Loop - -```sui -while window_should_close() == false do - # === PHYSICS STEP === - - # 1. Detect collisions between all geometries - ode_space_collide(world, space, contactgroup) - - # 2. Simulate physics - ode_world_step(world, 1.0 / 60.0) # 60 FPS timestep - - # 3. Clear contact group to avoid double-application - ode_joint_group_empty(contactgroup) - - # === RENDERING STEP === - - # Get current position - let mut x = 0.0 - let mut y = 0.0 - let mut z = 0.0 - ode_body_get_position(body, &x, &y, &z) - - # Draw - begin_drawing() - clear_background(135, 206, 235, 255) # Sky blue - begin_mode3d(0.0, 2.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 45.0, 0) - - draw_cube(x, y, z, 1.0, 1.0, 1.0, 255, 0, 0, 255) # Red cube - draw_cube(0.0, -1.0, 0.0, 20.0, 0.1, 20.0, 34, 139, 34, 255) # Green ground - - end_mode3d() - end_drawing() -end -``` - -### Step 5: Cleanup - -Always destroy objects in reverse order of creation: - -```sui -ode_joint_group_destroy(contactgroup) -ode_geom_destroy(geom) -ode_body_destroy(body) -ode_space_destroy(space) -ode_world_destroy(world) -ode_close() -close_window() -``` - -## Available Physics Functions - -### World Management -- `ode_init()` - Initialize ODE -- `ode_close()` - Shutdown ODE -- `ode_world_create() -> *()` - Create a world -- `ode_world_destroy(world)` - Destroy world -- `ode_world_set_gravity(world, x, y, z)` - Set gravity vector -- `ode_world_step(world, timestep)` - Advance simulation - -### Body Management -- `ode_body_create(world) -> *()` - Create a dynamic body -- `ode_body_destroy(body)` -- `ode_body_set_position(body, x, y, z)` -- `ode_body_get_position(body, &x, &y, &z)` - Retrieve position via pointers -- `ode_body_set_linear_vel(body, vx, vy, vz)` -- `ode_body_get_linear_vel(body, &vx, &vy, &vz)` -- `ode_body_set_rotation(body, w, x, y, z)` - Set quaternion rotation -- `ode_body_get_rotation(body, &w, &x, &y, &z)` - Get quaternion rotation -- `ode_body_set_box_mass(body, density, width, height, length)` - -### Collision Shapes (Geometries) -- `ode_create_box_geom(space, width, height, length) -> *()` - Create box shape -- `ode_create_plane_geom(space, nx, ny, nz, d) -> *()` - Create plane shape -- `ode_geom_set_body(geom, body)` - Attach geometry to body -- `ode_geom_destroy(geom)` - -### Collision Spaces -- `ode_simple_space_create(parent) -> *()` - Create simple space -- `ode_space_destroy(space)` -- `ode_space_collide(world, space, contactgroup)` - **Important**: Detect collisions -- `ode_joint_group_create(max_size) -> *()` - Create contact joint group -- `ode_joint_group_destroy(group)` -- `ode_joint_group_empty(group)` - **Important**: Clear contacts after step - -## Common Patterns - -### Adding Bounce/Restitution - -Modify the contact properties in libsuicmez.c `near_callback()`: - -```c -contact[i].surface.bounce = 0.5; // 0 = no bounce, 1 = perfect bounce -contact[i].surface.bounce_vel = 0.1; -``` - -### Applying Forces - -```sui -# Set velocity directly -ode_body_set_linear_vel(body, 10.0, 0.0, 0.0) -``` - -Note: ODE also supports force/torque application through lower-level APIs. - -### Multiple Objects - -Create arrays of bodies and simulate them in a loop: - -```sui -let bodies_count = 5 -# In main loop: -let mut i = 0 -while i < bodies_count do - ode_body_get_position(bodies[i], &x, &y, &z) - draw_cube(x, y, z, 1.0, 1.0, 1.0, 255, 0, 0, 255) - i = i + 1 -end -``` - -## Advanced Topics - -### Custom Contact Properties - -Edit `suic_ode_set_contact_erp()` and `suic_ode_set_contact_cfm()` to tune physics: - -- **ERP** (Error Reduction Parameter): 0-1, controls how fast constraint violations are fixed -- **CFM** (Constraint Force Mixing): Soft constraint parameter, adds damping - -### Quaternion Rotations - -ODE uses quaternions for 3D rotations. They're represented as (w, x, y, z): - -```sui -# Identity rotation -ode_body_set_rotation(body, 1.0, 0.0, 0.0, 0.0) - -# Get current rotation -let mut w = 0.0 -let mut x = 0.0 -let mut y = 0.0 -let mut z = 0.0 -ode_body_get_rotation(body, &w, &x, &y, &z) -``` - -### Performance Optimization - -For large numbers of objects: - -1. Use `dBVHSpaceCreate()` (not yet exposed) instead of simple space -2. Reduce collision pairs by using collision filtering -3. Use larger timesteps (but beware stability) -4. Implement sleeping/deactivation for static objects - -## Example: Bouncing Ball Game - -See `tests/game_3d.sui` for a complete working example of: -- Physics world setup -- Dynamic falling cube -- Ground plane -- Collision detection -- 3D rendering - -Compile and run: - -```bash -cargo run tests/game_3d.sui -gcc tests/game_3d.c libsuicmez/libsuicmez.c $(pkg-config --cflags --libs raylib ode) -o game -./game -``` - -## Troubleshooting - -### "Cube falls through ground" -- Ensure `ode_space_collide()` is called **before** `ode_world_step()` -- Ensure contact group is created with `ode_joint_group_create()` -- Call `ode_joint_group_empty()` after each step - -### Jittery Physics -- Reduce timestep (smaller value in `ode_world_step()`) -- Increase ERP with `suic_ode_set_contact_erp()` -- Reduce CFM with `suic_ode_set_contact_cfm()` - -### Objects moving too slow/fast -- Check gravity: `ode_world_set_gravity(world, 0.0, -9.81, 0.0)` -- Check body mass: `ode_body_set_box_mass(body, density, w, h, l)` -- Check initial velocity: `ode_body_set_linear_vel(body, vx, vy, vz)` - -## Next Steps - -The Sui language is now ready for 3D game development! Future enhancements could include: - -- Higher-level GameObject system wrapping physics + rendering -- Additional collision shapes (spheres, cylinders, meshes) -- Particle systems -- Audio integration -- Input handling improvements -- Scripting for game logic - -Happy game developing! šŸŽ® diff --git a/README.md b/README.md deleted file mode 100644 index 33bb998..0000000 --- a/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# ODE Physics Engine Integration - -## āœ… ODE Integration Complete - -Full Open Dynamics Engine (ODE) support has been integrated into suicmez for 3D physics simulation, perfect for voxel games! - -## Available ODE Functions - -### Initialization and Cleanup -- `ode_init()` - Initialize the ODE library -- `ode_close()` - Clean up ODE resources - -### World Management -- `ode_world_create()` - Create a new physics world -- `ode_world_destroy(world)` - Destroy a physics world -- `ode_world_set_gravity(world, x, y, z)` - Set world gravity -- `ode_world_step(world, stepsize)` - Advance physics simulation - -### Rigid Bodies -- `ode_body_create(world)` - Create a new rigid body -- `ode_body_destroy(body)` - Destroy a rigid body -- `ode_body_set_position(body, x, y, z)` - Set body position -- `ode_body_set_linear_vel(body, x, y, z)` - Set linear velocity - -### Mass and Geometry -- `ode_body_set_box_mass(body, density, lx, ly, lz)` - Set box-shaped mass -- `ode_create_box_geom(space, lx, ly, lz)` - Create box collision geometry -- `ode_geom_set_body(geom, body)` - Attach geometry to body -- `ode_geom_destroy(geom)` - Destroy geometry - -### Collision Spaces -- `ode_simple_space_create(parent)` - Create collision space -- `ode_space_destroy(space)` - Destroy collision space - -## Example Usage - -```sui -# Initialize physics -ode_init() - -# Create world with gravity -let world = ode_world_create() -let space = ode_simple_space_create(0 as *()) # null parent -ode_world_set_gravity(world, 0.0, -9.81, 0.0) - -# Create a falling voxel/box -let body = ode_body_create(world) -ode_body_set_box_mass(body, 1.0, 1.0, 1.0, 1.0) # 1x1x1 meter box -ode_body_set_position(body, 0.0, 5.0, 0.0) # Start 5 units up - -let geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) -ode_geom_set_body(geom, body) - -# Simulate physics -let mut i = 0 -while i < 100 do - ode_world_step(world, 0.016) # 60 FPS - i = i + 1 -end - -# Cleanup -ode_geom_destroy(geom) -ode_body_destroy(body) -ode_space_destroy(space) -ode_world_destroy(world) -ode_close() -``` - -## Compilation - -Use the updated compile scripts which now include ODE: - -```bash -./compile.sh tests/your_ode_program.sui -./compile_and_run.sh tests/your_ode_program.sui -``` - -## ODE Version - -Currently using: **ODE 0.16.6** - -- Real-time rigid body dynamics -- Collision detection -- Joint constraints -- Stable simulation for games - -All ODE features are now available through suicmez for building physics-based voxel games! -ODE_INTEGRATION.md \ No newline at end of file diff --git a/compile.sh b/compile.sh deleted file mode 100755 index 17832da..0000000 --- a/compile.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash -# Simple helper script to compile Sui code and link with libsuicmez - -if [ $# -eq 0 ]; then - echo "Usage: ./compile.sh [output_name]" - echo "" - echo "Example:" - echo " ./compile.sh tests/structs.sui" - echo " ./compile.sh tests/structs.sui my_program" - exit 1 -fi - -INPUT_SUI="$1" -OUTPUT_NAME="${2:-${INPUT_NAME%.sui}}" - -if [ ! -f "$INPUT_SUI" ]; then - echo "Error: File not found: $INPUT_SUI" - exit 1 -fi - -# Compile Sui to C -echo "Compiling $INPUT_SUI to C..." -cargo run "$INPUT_SUI" || exit 1 - -# Get the C file name (should be next to the .sui file) -C_FILE="${INPUT_SUI%.sui}.c" -OUTPUT_BINARY="${INPUT_SUI%.sui}.o" - -if [ -n "$2" ]; then - OUTPUT_BINARY="$2" -fi - -if [ ! -f "$C_FILE" ]; then - echo "Error: Generated C file not found: $C_FILE" - exit 1 -fi - -# Get raylib compile and link flags -RAYLIB_CFLAGS=$(pkg-config --cflags raylib 2>/dev/null || echo "-I/usr/include") -RAYLIB_LIBS=$(pkg-config --libs raylib 2>/dev/null || echo "-lraylib -lm") - -# Get ODE compile and link flags -ODE_CFLAGS=$(pkg-config --cflags ode 2>/dev/null || echo "-I/usr/include") -ODE_LIBS=$(pkg-config --libs ode 2>/dev/null || echo "-lode -lm") - -# Compile C to executable with raylib and ODE support -echo "Compiling C code and linking with libsuicmez, raylib, and ODE..." -gcc "$C_FILE" libsuicmez/libsuicmez.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -o "$OUTPUT_BINARY" || exit 1 - -echo "āœ“ Successfully created: $OUTPUT_BINARY" -echo " Run with: ./$OUTPUT_BINARY" diff --git a/compile_and_run.sh b/compile_and_run.sh deleted file mode 100755 index 008b47d..0000000 --- a/compile_and_run.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash -# Compile Sui source to C, then compile and run the executable - -if [ $# -eq 0 ]; then - echo "Usage: ./compile_and_run.sh [program_args...]" - echo "" - echo "Examples:" - echo " ./compile_and_run.sh tests/structs.sui" - echo " ./compile_and_run.sh tests/myprogram.sui arg1 arg2" - exit 1 -fi - -INPUT_SUI="$1" -shift # Remove first argument, keep the rest as program args - -if [ ! -f "$INPUT_SUI" ]; then - echo "Error: File not found: $INPUT_SUI" - exit 1 -fi - -# Determine output names -C_FILE="${INPUT_SUI%.sui}.c" -# Extract just the filename without extension for the temp binary -BINARY_NAME=$(basename "${INPUT_SUI%.sui}") -OUTPUT_BINARY="/tmp/suic_$BINARY_NAME" - -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "Step 1: Compiling Sui to C..." -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - -if ! cargo run "$INPUT_SUI" > /dev/null 2>&1; then - echo "" - echo "āœ— Sui compilation failed" - exit 1 -fi - -if [ ! -f "$C_FILE" ]; then - echo "āœ— Error: Generated C file not found: $C_FILE" - exit 1 -fi - -echo "āœ“ C file generated: $C_FILE" -echo "" - -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "Step 2: Compiling C to executable..." -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - -# Get raylib compile and link flags -RAYLIB_CFLAGS=$(pkg-config --cflags raylib 2>/dev/null || echo "-I/usr/include") -RAYLIB_LIBS=$(pkg-config --libs raylib 2>/dev/null || echo "-lraylib -lm") - -# Get ODE compile and link flags -ODE_CFLAGS=$(pkg-config --cflags ode 2>/dev/null || echo "-I/usr/include") -ODE_LIBS=$(pkg-config --libs ode 2>/dev/null || echo "-lode -lm") - -if ! gcc "$C_FILE" libsuicmez/libsuicmez.c $RAYLIB_CFLAGS $RAYLIB_LIBS $ODE_CFLAGS $ODE_LIBS -o "$OUTPUT_BINARY" 2>&1; then - echo "" - echo "āœ— C compilation failed" - exit 1 -fi - -echo "āœ“ Executable created: $OUTPUT_BINARY" -echo "" - -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "Step 3: Running program..." -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "" - -# Run with any additional arguments passed to this script -"$OUTPUT_BINARY" "$@" -EXIT_CODE=$? - -echo "" -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -if [ $EXIT_CODE -eq 0 ]; then - echo "āœ“ Program completed successfully" -else - echo "āœ— Program exited with code: $EXIT_CODE" -fi -echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - -exit $EXIT_CODE diff --git a/libsuicmez/libsuicmez.c b/libsuicmez/libsuicmez.c deleted file mode 100644 index 46fd414..0000000 --- a/libsuicmez/libsuicmez.c +++ /dev/null @@ -1,617 +0,0 @@ -#include "raylib.h" -#include "libsuicmez.h" -#include -#include -#include - -// Simple garbage collection allocator -// This is a basic implementation that tracks allocations -// For production, consider using a more robust GC library - -#define MAX_TRACKED_ALLOCATIONS 10000 - -typedef struct { - void* ptr; - size_t size; - int in_use; -} AllocationInfo; - -static AllocationInfo tracked_allocations[MAX_TRACKED_ALLOCATIONS]; -static int allocation_count = 0; -static const char* last_error = NULL; - -// Simple linear search to find allocation -static int find_allocation(void* ptr) { - for (int i = 0; i < allocation_count; i++) { - if (tracked_allocations[i].ptr == ptr && tracked_allocations[i].in_use) { - return i; - } - } - return -1; -} - -// GC-aware allocator -void* gc_suic_alloc(size_t size) { - if (size == 0) { - return NULL; - } - - void* ptr = malloc(size); - if (!ptr) { - last_error = "Memory allocation failed"; - return NULL; - } - - // Track this allocation - if (allocation_count < MAX_TRACKED_ALLOCATIONS) { - tracked_allocations[allocation_count].ptr = ptr; - tracked_allocations[allocation_count].size = size; - tracked_allocations[allocation_count].in_use = 1; - allocation_count++; - } else { - last_error = "Too many tracked allocations"; - free(ptr); - return NULL; - } - - return ptr; -} - -// Free memory (called by gc_suic_free) -void suic_gc_free(void* ptr) { - if (!ptr) return; - - int idx = find_allocation(ptr); - if (idx >= 0) { - tracked_allocations[idx].in_use = 0; - free(ptr); - } -} - -// Error handling -const char *suic_last_error(void) { - return last_error ? last_error : "No error"; -} - -void suic_clear_error(void) { - last_error = NULL; -} - -// Logging -static suic_log_level current_log_level = SUIC_LOG_ALL; - -void suic_set_log_level(suic_log_level level) { - current_log_level = level; -} - -// Window management -bool suic_init_window(int width, int height, const char *title) { - InitWindow(width, height, title); - return !WindowShouldClose(); -} - -void suic_close_window(void) { - CloseWindow(); -} - -bool suic_window_should_close(void) { - return WindowShouldClose(); -} - -void suic_set_target_fps(int fps) { - SetTargetFPS(fps); -} - -// Drawing -void suic_begin_drawing(void) { - BeginDrawing(); -} - -void suic_end_drawing(void) { - EndDrawing(); -} - -void suic_clear_background(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - ClearBackground((Color){r, g, b, a}); -} - -// 3D mode -Camera3D suic_to_rl_camera3d(suic_camera3d cam) { - return (Camera3D){ - .position = suic_to_rl_vec3(cam.position), - .target = suic_to_rl_vec3(cam.target), - .up = suic_to_rl_vec3(cam.up), - .fovy = cam.fovy, - .projection = cam.projection - }; -} - -void suic_begin_mode3d(float pos_x, float pos_y, float pos_z, float target_x, float target_y, float target_z, float up_x, float up_y, float up_z, float fovy, int projection) { - Camera3D camera = { - .position = (Vector3){pos_x, pos_y, pos_z}, - .target = (Vector3){target_x, target_y, target_z}, - .up = (Vector3){up_x, up_y, up_z}, - .fovy = fovy, - .projection = projection - }; - BeginMode3D(camera); -} - -void suic_end_mode3d(void) { - EndMode3D(); -} - -// 3D Drawing -void suic_draw_cube(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - DrawCube((Vector3){x, y, z}, width, height, length, (Color){r, g, b, a}); -} - -void suic_draw_cube_wires(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - DrawCubeWires((Vector3){x, y, z}, width, height, length, (Color){r, g, b, a}); -} - -// Input -bool suic_is_key_down(int key) { - return IsKeyDown(key); -} - -bool suic_is_mouse_button_down(int b) { - return IsMouseButtonDown(b); -} - -suic_vec2 suic_get_mouse_position(void) { - Vector2 pos = GetMousePosition(); - return (suic_vec2){pos.x, pos.y}; -} - -// Image and Texture -suic_image_handle suic_image_load(const char *path) { - Image img = LoadImage(path); - return (suic_image_handle){img, (img.data != NULL) ? true : false}; -} - -void suic_image_free(suic_image_handle *img) { - if (img && img->valid) { - UnloadImage(img->value); - img->valid = false; - } -} - -suic_texture_handle suic_texture_load(const char *path) { - Texture2D tex = LoadTexture(path); - return (suic_texture_handle){tex, (tex.id != 0) ? true : false}; -} - -suic_texture_handle suic_texture_from_image(suic_image_handle img) { - if (!img.valid) { - return (suic_texture_handle){0, false}; - } - Texture2D tex = LoadTextureFromImage(img.value); - return (suic_texture_handle){tex, (tex.id != 0) ? true : false}; -} - -void suic_texture_free(suic_texture_handle *tex) { - if (tex && tex->valid) { - UnloadTexture(tex->value); - tex->valid = false; - } -} - -void suic_draw_texture(suic_texture_handle tex, int x, int y, unsigned char r, - unsigned char g, unsigned char b, unsigned char a) { - if (tex.valid) { - DrawTexture(tex.value, x, y, (Color){r, g, b, a}); - } -} - -// Audio -bool suic_audio_init(void) { - InitAudioDevice(); - return IsAudioDeviceReady(); -} - -void suic_audio_close(void) { - CloseAudioDevice(); -} - -suic_sound_handle suic_sound_load(const char *path) { - Sound snd = LoadSound(path); - return (suic_sound_handle){snd, (snd.frameCount > 0) ? true : false}; -} - -void suic_sound_play(suic_sound_handle snd) { - if (snd.valid) { - PlaySound(snd.value); - } -} - -void suic_sound_set_volume(suic_sound_handle snd, float volume) { - if (snd.valid) { - SetSoundVolume(snd.value, volume); - } -} - -void suic_sound_free(suic_sound_handle *snd) { - if (snd && snd->valid) { - UnloadSound(snd->value); - snd->valid = false; - } -} - -// Raycasting -suic_ray suic_get_mouse_ray(suic_vec2 mouse, suic_camera3d cam) { - Ray r = GetMouseRay( - (Vector2){mouse.x, mouse.y}, - suic_to_rl_camera3d(cam) - ); - return (suic_ray){ - .origin = (suic_vec3){r.position.x, r.position.y, r.position.z}, - .direction = (suic_vec3){r.direction.x, r.direction.y, r.direction.z} - }; -} - -suic_rayhit suic_raycast_aabb(suic_ray ray, suic_aabb box) { - Ray r = (Ray){ - .position = (Vector3){ray.origin.x, ray.origin.y, ray.origin.z}, - .direction = (Vector3){ray.direction.x, ray.direction.y, ray.direction.z} - }; - - BoundingBox bbox = (BoundingBox){ - .min = (Vector3){box.min.x, box.min.y, box.min.z}, - .max = (Vector3){box.max.x, box.max.y, box.max.z} - }; - - RayCollision collision = GetRayCollisionBox(r, bbox); - - return (suic_rayhit){ - .hit = collision.hit, - .distance = collision.distance, - .point = (suic_vec3){collision.point.x, collision.point.y, collision.point.z}, - .normal = (suic_vec3){collision.normal.x, collision.normal.y, collision.normal.z} - }; -} - -// ODE Physics Engine Implementation -static int ode_initialized = 0; - -void suic_ode_init(void) { - if (!ode_initialized) { - dInitODE(); - ode_initialized = 1; - } -} - -void suic_ode_close(void) { - if (ode_initialized) { - dCloseODE(); - ode_initialized = 0; - } -} - -suic_ode_world_id suic_ode_world_create(void) { - return dWorldCreate(); -} - -void suic_ode_world_destroy(suic_ode_world_id world) { - if (world) { - dWorldDestroy(world); - } -} - -void suic_ode_world_set_gravity(suic_ode_world_id world, dReal x, dReal y, dReal z) { - if (world) { - dWorldSetGravity(world, x, y, z); - } -} - -void suic_ode_world_step(suic_ode_world_id world, dReal stepsize) { - if (world) { - dWorldStep(world, stepsize); - } -} - -// Body management -suic_ode_body_id suic_ode_body_create(suic_ode_world_id world) { - return dBodyCreate(world); -} - -void suic_ode_body_destroy(suic_ode_body_id body) { - if (body) { - dBodyDestroy(body); - } -} - -void suic_ode_body_set_position(suic_ode_body_id body, dReal x, dReal y, dReal z) { - if (body) { - dBodySetPosition(body, x, y, z); - } -} - -void suic_ode_body_set_linear_vel(suic_ode_body_id body, dReal x, dReal y, dReal z) { - if (body) { - dBodySetLinearVel(body, x, y, z); - } -} - -void suic_ode_body_get_position(suic_ode_body_id body, float *x, float *y, float *z) { - if (body) { - const dReal *pos = dBodyGetPosition(body); - *x = (float)pos[0]; - *y = (float)pos[1]; - *z = (float)pos[2]; - } -} - -// Mass and geometry -void suic_ode_body_set_box_mass(suic_ode_body_id body, dReal density, dReal lx, dReal ly, dReal lz) { - if (body) { - dMass mass; - dMassSetBox(&mass, density, lx, ly, lz); - dBodySetMass(body, &mass); - } -} - -suic_ode_geom_id suic_ode_create_box_geom(suic_ode_space_id space, dReal lx, dReal ly, dReal lz) { - return dCreateBox(space, lx, ly, lz); -} - -suic_ode_geom_id suic_ode_create_plane_geom(suic_ode_space_id space, dReal a, dReal b, dReal c, dReal d) { - return dCreatePlane(space, a, b, c, d); -} - -void suic_ode_geom_set_body(suic_ode_geom_id geom, suic_ode_body_id body) { - if (geom) { - dGeomSetBody(geom, body); - } -} - -void suic_ode_geom_destroy(suic_ode_geom_id geom) { - if (geom) { - dGeomDestroy(geom); - } -} - -// Collision space -suic_ode_space_id suic_ode_simple_space_create(suic_ode_space_id parent) { - return dSimpleSpaceCreate(parent); -} - -void suic_ode_space_destroy(suic_ode_space_id space) { - if (space) { - dSpaceDestroy(space); - } -} - -// ============================================================================ -// COLLISION DETECTION AND CONTACT JOINTS -// ============================================================================ - -// Global contact configuration -static dReal contact_max_force = 10000.0; -static dReal contact_erp = 0.8; // Error reduction parameter -static dReal contact_cfm = 0.00001; // Constraint force mixing - -// Store world and contactgroup for collision callback -typedef struct { - dWorldID world; - dJointGroupID contactgroup; -} CollisionContext; - -// Collision callback for detecting contacts between geometries -static void near_callback(void *data, dGeomID o1, dGeomID o2) { - CollisionContext *ctx = (CollisionContext*)data; - dBodyID b1 = dGeomGetBody(o1); - dBodyID b2 = dGeomGetBody(o2); - - // Don't process if both bodies are static or same body - if ((b1 && b2 && b1 == b2) || (!b1 && !b2)) { - return; - } - - const int N = 4; // Max contacts per collision - dContact contact[N]; - - // Check for collisions - int n = dCollide(o1, o2, N, &contact[0].geom, sizeof(dContact)); - if (n > 0) { - for (int i = 0; i < n; i++) { - // Set contact properties - contact[i].surface.mu = 0.5; // Friction coefficient - contact[i].surface.mu2 = 0.5; - contact[i].surface.bounce = 0.1; // Bounciness - contact[i].surface.bounce_vel = 0.1; - contact[i].surface.mode = dContactBounce | dContactSoftERP | dContactSoftCFM; - contact[i].surface.soft_erp = contact_erp; - contact[i].surface.soft_cfm = contact_cfm; - - // Create contact joint - dJointID c = dJointCreateContact(ctx->world, ctx->contactgroup, &contact[i]); - dJointAttach(c, b1, b2); - } - } -} - -void suic_ode_space_collide(suic_ode_world_id world, suic_ode_space_id space, suic_ode_joint_group_id contactgroup) { - if (space && contactgroup && world) { - CollisionContext ctx = {.world = world, .contactgroup = contactgroup}; - dSpaceCollide(space, (void*)&ctx, &near_callback); - } -} - -suic_ode_joint_group_id suic_ode_joint_group_create(int max_size) { - return dJointGroupCreate(max_size); -} - -void suic_ode_joint_group_destroy(suic_ode_joint_group_id group) { - if (group) { - dJointGroupDestroy(group); - } -} - -void suic_ode_joint_group_empty(suic_ode_joint_group_id group) { - if (group) { - dJointGroupEmpty(group); - } -} - -void suic_ode_set_contact_max_force(dReal force) { - contact_max_force = force; -} - -void suic_ode_set_contact_erp(dReal erp) { - contact_erp = erp; -} - -void suic_ode_set_contact_cfm(dReal cfm) { - contact_cfm = cfm; -} - -// ============================================================================ -// ADDITIONAL BODY FUNCTIONS -// ============================================================================ - -void suic_ode_body_get_linear_vel(suic_ode_body_id body, float *x, float *y, float *z) { - if (body) { - const dReal *vel = dBodyGetLinearVel(body); - *x = (float)vel[0]; - *y = (float)vel[1]; - *z = (float)vel[2]; - } -} - -void suic_ode_body_get_rotation(suic_ode_body_id body, float *q_w, float *q_x, float *q_y, float *q_z) { - if (body) { - const dReal *q = dBodyGetQuaternion(body); - *q_w = (float)q[0]; - *q_x = (float)q[1]; - *q_y = (float)q[2]; - *q_z = (float)q[3]; - } -} - -void suic_ode_body_set_rotation(suic_ode_body_id body, dReal q_w, dReal q_x, dReal q_y, dReal q_z) { - if (body) { - dQuaternion q; - q[0] = q_w; - q[1] = q_x; - q[2] = q_y; - q[3] = q_z; - dBodySetQuaternion(body, q); - } -} - -// ============================================================================ -// GAME OBJECT SYSTEM - Unified Physics & Rendering -// ============================================================================ - -suic_game_object* suic_game_object_create_box( - suic_ode_world_id world, - suic_ode_space_id space, - float x, float y, float z, - float width, float height, float length, - float density, - unsigned char r, unsigned char g, unsigned char b, unsigned char a -) { - suic_game_object* obj = (suic_game_object*)gc_suic_alloc(sizeof(suic_game_object)); - if (!obj) return NULL; - - // Create physics body - obj->body = dBodyCreate(world); - if (!obj->body) { - suic_gc_free(obj); - return NULL; - } - - // Set position - dBodySetPosition(obj->body, x, y, z); - - // Create and attach geometry - obj->geom = dCreateBox(space, width, height, length); - if (!obj->geom) { - dBodyDestroy(obj->body); - suic_gc_free(obj); - return NULL; - } - - dGeomSetBody(obj->geom, obj->body); - - // Set mass - dMass mass; - dMassSetBox(&mass, density, width, height, length); - dBodySetMass(obj->body, &mass); - - // Store rendering data - obj->width = width; - obj->height = height; - obj->length = length; - obj->r = r; - obj->g = g; - obj->b = b; - obj->a = a; - obj->shape_type = 0; // 0 = box - - return obj; -} - -void suic_game_object_destroy(suic_game_object* obj) { - if (obj) { - if (obj->geom) { - dGeomDestroy(obj->geom); - } - if (obj->body) { - dBodyDestroy(obj->body); - } - suic_gc_free(obj); - } -} - -void suic_game_object_set_position(suic_game_object* obj, float x, float y, float z) { - if (obj && obj->body) { - dBodySetPosition(obj->body, x, y, z); - } -} - -void suic_game_object_get_position(suic_game_object* obj, float *x, float *y, float *z) { - if (obj && obj->body) { - const dReal *pos = dBodyGetPosition(obj->body); - *x = (float)pos[0]; - *y = (float)pos[1]; - *z = (float)pos[2]; - } -} - -void suic_game_object_set_velocity(suic_game_object* obj, float x, float y, float z) { - if (obj && obj->body) { - dBodySetLinearVel(obj->body, x, y, z); - } -} - -void suic_game_object_get_velocity(suic_game_object* obj, float *x, float *y, float *z) { - if (obj && obj->body) { - const dReal *vel = dBodyGetLinearVel(obj->body); - *x = (float)vel[0]; - *y = (float)vel[1]; - *z = (float)vel[2]; - } -} - -void suic_game_object_draw(suic_game_object* obj) { - if (obj && obj->body) { - float x, y, z; - suic_game_object_get_position(obj, &x, &y, &z); - - if (obj->shape_type == 0) { // Box - DrawCube( - (Vector3){x, y, z}, - obj->width, obj->height, obj->length, - (Color){obj->r, obj->g, obj->b, obj->a} - ); - // Draw wireframe for visual clarity - DrawCubeWires( - (Vector3){x, y, z}, - obj->width, obj->height, obj->length, - (Color){0, 0, 0, 200} - ); - } - } -} diff --git a/libsuicmez/libsuicmez.h b/libsuicmez/libsuicmez.h index baafec8..ef22ea7 100644 --- a/libsuicmez/libsuicmez.h +++ b/libsuicmez/libsuicmez.h @@ -3,16 +3,10 @@ #include #include -#include -#include -// Raylib support +// Forward include raylib (or include it in the .c and keep only forward decls) #include "raylib.h" -// ODE support -#include - -// Logging levels typedef enum suic_log_level { SUIC_LOG_ALL = 0, SUIC_LOG_INFO = 1, @@ -21,12 +15,11 @@ typedef enum suic_log_level { SUIC_LOG_NONE = 4 } suic_log_level; -// Error handling const char *suic_last_error(void); void suic_clear_error(void); + void suic_set_log_level(suic_log_level level); -// Vec types typedef struct suic_vec2 { float x, y; } suic_vec2; @@ -35,62 +28,54 @@ typedef struct suic_vec3 { float x, y, z; } suic_vec3; -// Vector conversion helpers static inline Vector2 suic_to_rl_vec2(suic_vec2 v) { return (Vector2){v.x, v.y}; } - static inline Vector3 suic_to_rl_vec3(suic_vec3 v) { return (Vector3){v.x, v.y, v.z}; } - static inline suic_vec2 suic_from_rl_vec2(Vector2 v) { return (suic_vec2){v.x, v.y}; } - static inline suic_vec3 suic_from_rl_vec3(Vector3 v) { return (suic_vec3){v.x, v.y, v.z}; } -// Window management +// Must be called before any GPU resources (textures, models) are created. bool suic_init_window(int width, int height, const char *title); void suic_close_window(void); + bool suic_window_should_close(void); void suic_set_target_fps(int fps); -// Drawing (2D) +// Frame boundaries (2D) void suic_begin_drawing(void); void suic_end_drawing(void); -void suic_clear_background(unsigned char r, unsigned char g, unsigned char b, unsigned char a); +void suic_clear_background(unsigned char r, unsigned char g, unsigned char b, + unsigned char a); -// 3D Camera +// 3D mode boundaries typedef struct suic_camera3d { suic_vec3 position; suic_vec3 target; suic_vec3 up; float fovy; - int projection; // CameraProjection + int projection; // map to CameraProjection } suic_camera3d; Camera3D suic_to_rl_camera3d(suic_camera3d cam); -void suic_begin_mode3d(float pos_x, float pos_y, float pos_z, float target_x, float target_y, float target_z, float up_x, float up_y, float up_z, float fovy, int projection); + +void suic_begin_mode3d(suic_camera3d cam); void suic_end_mode3d(void); -// 3D Drawing -void suic_draw_cube(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a); -void suic_draw_cube_wires(float x, float y, float z, float width, float height, float length, unsigned char r, unsigned char g, unsigned char b, unsigned char a); - -// Input bool suic_is_key_down(int key); bool suic_is_mouse_button_down(int b); suic_vec2 suic_get_mouse_position(void); -// Images and Textures typedef struct suic_image_handle { Image value; bool valid; } suic_image_handle; - typedef struct suic_texture_handle { Texture2D value; bool valid; @@ -102,12 +87,13 @@ void suic_image_free(suic_image_handle *img); suic_texture_handle suic_texture_load(const char *path); suic_texture_handle suic_texture_from_image(suic_image_handle img); void suic_texture_free(suic_texture_handle *tex); + +// Drawing a texture (basic) void suic_draw_texture(suic_texture_handle tex, int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a); -// Audio -bool suic_audio_init(void); -void suic_audio_close(void); +bool suic_audio_init(void); // wraps InitAudioDevice +void suic_audio_close(void); // wraps CloseAudioDevice typedef struct suic_sound_handle { Sound value; @@ -119,7 +105,6 @@ void suic_sound_play(suic_sound_handle snd); void suic_sound_set_volume(suic_sound_handle snd, float volume); void suic_sound_free(suic_sound_handle *snd); -// Raycasting typedef struct suic_ray { suic_vec3 origin; suic_vec3 direction; @@ -132,102 +117,14 @@ typedef struct suic_rayhit { suic_vec3 normal; } suic_rayhit; +// Ray from camera + mouse +suic_ray suic_get_mouse_ray(suic_vec2 mouse, suic_camera3d cam); + +// AABB ray test (for chunk culling / picking helpers) typedef struct suic_aabb { suic_vec3 min; suic_vec3 max; } suic_aabb; - -suic_ray suic_get_mouse_ray(suic_vec2 mouse, suic_camera3d cam); suic_rayhit suic_raycast_aabb(suic_ray ray, suic_aabb box); -// GC-aware allocator (core functionality) -void* gc_suic_alloc(size_t size); -void suic_gc_free(void* ptr); - -// ODE Physics Engine Support -// ODE types (opaque pointers) -typedef dWorldID suic_ode_world_id; -typedef dSpaceID suic_ode_space_id; -typedef dBodyID suic_ode_body_id; -typedef dGeomID suic_ode_geom_id; -typedef dJointID suic_ode_joint_id; -typedef dJointGroupID suic_ode_joint_group_id; - -// Vector types for ODE (matching ODE's dReal which is double) -typedef struct suic_ode_vector3 { - dReal x, y, z; -} suic_ode_vector3; - -typedef struct suic_ode_quaternion { - dReal w, x, y, z; // ODE quaternion format: w,x,y,z -} suic_ode_quaternion; - -// Basic ODE functions -void suic_ode_init(void); -void suic_ode_close(void); -suic_ode_world_id suic_ode_world_create(void); -void suic_ode_world_destroy(suic_ode_world_id world); -void suic_ode_world_set_gravity(suic_ode_world_id world, dReal x, dReal y, dReal z); -void suic_ode_world_step(suic_ode_world_id world, dReal stepsize); - -// Body management -suic_ode_body_id suic_ode_body_create(suic_ode_world_id world); -void suic_ode_body_destroy(suic_ode_body_id body); -void suic_ode_body_set_position(suic_ode_body_id body, dReal x, dReal y, dReal z); -void suic_ode_body_set_linear_vel(suic_ode_body_id body, dReal x, dReal y, dReal z); -void suic_ode_body_get_position(suic_ode_body_id body, float *x, float *y, float *z); - -// Mass and geometry -void suic_ode_body_set_box_mass(suic_ode_body_id body, dReal density, dReal lx, dReal ly, dReal lz); -suic_ode_geom_id suic_ode_create_box_geom(suic_ode_space_id space, dReal lx, dReal ly, dReal lz); -suic_ode_geom_id suic_ode_create_plane_geom(suic_ode_space_id space, dReal a, dReal b, dReal c, dReal d); -void suic_ode_geom_set_body(suic_ode_geom_id geom, suic_ode_body_id body); -void suic_ode_geom_destroy(suic_ode_geom_id geom); - -// Collision space -suic_ode_space_id suic_ode_simple_space_create(suic_ode_space_id parent); -void suic_ode_space_destroy(suic_ode_space_id space); - -// Collision detection and contact joints -void suic_ode_space_collide(suic_ode_world_id world, suic_ode_space_id space, suic_ode_joint_group_id contactgroup); -suic_ode_joint_group_id suic_ode_joint_group_create(int max_size); -void suic_ode_joint_group_destroy(suic_ode_joint_group_id group); -void suic_ode_joint_group_empty(suic_ode_joint_group_id group); - -// Additional body functions -void suic_ode_body_get_linear_vel(suic_ode_body_id body, float *x, float *y, float *z); -void suic_ode_body_get_rotation(suic_ode_body_id body, float *q_w, float *q_x, float *q_y, float *q_z); -void suic_ode_body_set_rotation(suic_ode_body_id body, dReal q_w, dReal q_x, dReal q_y, dReal q_z); - -// Contact properties configuration -void suic_ode_set_contact_max_force(dReal force); -void suic_ode_set_contact_erp(dReal erp); -void suic_ode_set_contact_cfm(dReal cfm); - -// Game object system - unifies physics and rendering -typedef struct { - suic_ode_body_id body; - suic_ode_geom_id geom; - float width, height, length; // For box shapes - unsigned char r, g, b, a; // Color for rendering - int shape_type; // 0=box, 1=sphere, etc. -} suic_game_object; - -// Create and manage game objects -suic_game_object* suic_game_object_create_box( - suic_ode_world_id world, - suic_ode_space_id space, - float x, float y, float z, - float width, float height, float length, - float density, - unsigned char r, unsigned char g, unsigned char b, unsigned char a -); - -void suic_game_object_destroy(suic_game_object* obj); -void suic_game_object_set_position(suic_game_object* obj, float x, float y, float z); -void suic_game_object_get_position(suic_game_object* obj, float *x, float *y, float *z); -void suic_game_object_set_velocity(suic_game_object* obj, float x, float y, float z); -void suic_game_object_get_velocity(suic_game_object* obj, float *x, float *y, float *z); -void suic_game_object_draw(suic_game_object* obj); - #endif // LIBSUICMEZ_H diff --git a/simple.sui b/simple.sui new file mode 100644 index 0000000..173f651 --- /dev/null +++ b/simple.sui @@ -0,0 +1,3 @@ +fn simple() -> int do + 42 +end \ No newline at end of file diff --git a/simple_test.c b/simple_test.c new file mode 100644 index 0000000..9f52f8f --- /dev/null +++ b/simple_test.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +int simple_add(int x, int y); +int main(void); + + +int simple_add(int x, int y) { + (x + y); +} + +int main(void) { + int result = simple_add(5, 3); + return result; +} + diff --git a/simple_test.sui b/simple_test.sui new file mode 100644 index 0000000..65e17dc --- /dev/null +++ b/simple_test.sui @@ -0,0 +1,7 @@ +fn simple_add(x: int, y: int) -> int + x + y + +fn main() -> int do + let result = simple_add(5, 3) + result +end diff --git a/src/c_ir.rs b/src/c_ir.rs index aca4d2a..87ac418 100644 --- a/src/c_ir.rs +++ b/src/c_ir.rs @@ -8,25 +8,10 @@ pub enum CType { Ptr(Box), Struct(String), UnnamedStruct(Vec), - Array(Box), // heap-allocated array wrapper with data pointer, len, capacity + Array(Box, usize), // type and size Func(Vec, Box), // args and return } -impl CType { - /// Check if this type should be heap-allocated - pub fn is_heap_allocated(&self) -> bool { - matches!(self, CType::Array(_) | CType::Struct(_) | CType::Ptr(_)) - } - - /// Check if this is a copyable (stack-allocated) type - pub fn is_copyable(&self) -> bool { - matches!( - self, - CType::Void | CType::Int | CType::Float | CType::Bool | CType::Char | CType::Ptr(_) - ) - } -} - impl CType { pub fn to_string(&self) -> String { match self { @@ -44,10 +29,7 @@ impl CType { .collect(); format!("struct {{\n{}\n}}", field_strs.join("\n")) } - CType::Array(inner) => format!( - "struct sui_array_{}", - inner.to_string().replace(" ", "_").replace("*", "ptr") - ), + CType::Array(inner, size) => format!("{}[{}]", inner.to_string(), size), CType::Func(args, ret) => { let arg_strs: Vec = args.iter().map(|t| t.to_string()).collect(); format!("{} (*)({})", ret.to_string(), arg_strs.join(", ")) @@ -95,8 +77,6 @@ pub enum CExpr { Dot(Box, String), AddrOf(Box), Deref(Box), - Assign(Box, Box), // Assignment expression (lhs = rhs) - Ternary(Box, Box, Box), // cond ? then : else } #[derive(Debug, Clone)] diff --git a/src/c_lowerer/declaration_transpiler.rs b/src/c_lowerer/declaration_transpiler.rs index dedfcfa..5545674 100644 --- a/src/c_lowerer/declaration_transpiler.rs +++ b/src/c_lowerer/declaration_transpiler.rs @@ -137,7 +137,7 @@ impl DeclarationTranspiler { Some(TypeAnnot::Cons(name, args)) if args.is_empty() => convert_to_c_type(name), Some(TypeAnnot::Cons(name, _args)) => { // Generic types - for now just use the base name - Ok(CType::Ptr(Box::new(CType::Struct(name.clone())))) + Ok(CType::Struct(name.clone())) } Some(TypeAnnot::Ptr(inner)) => { let inner_type = self.type_annot_to_c_type(&Some(*inner.clone()))?; @@ -145,7 +145,6 @@ impl DeclarationTranspiler { } Some(TypeAnnot::Array(inner)) => { let inner_type = self.type_annot_to_c_type(&Some(*inner.clone()))?; - // Arrays are pointers to the element type Ok(CType::Ptr(Box::new(inner_type))) } Some(TypeAnnot::Tuple(fields)) => { @@ -179,6 +178,6 @@ pub fn convert_to_c_type(name: &String) -> Result { "float" => Ok(CType::Float), "bool" => Ok(CType::Bool), "string" => Ok(CType::Ptr(Box::new(CType::Char))), - _ => Ok(CType::Ptr(Box::new(CType::Struct(name.clone())))), // Assume heap-allocated struct + _ => Ok(CType::Struct(name.clone())), // Assume struct } } diff --git a/src/c_lowerer/statements_transpiler.rs b/src/c_lowerer/statements_transpiler.rs index 2038f25..e277af3 100644 --- a/src/c_lowerer/statements_transpiler.rs +++ b/src/c_lowerer/statements_transpiler.rs @@ -139,24 +139,9 @@ impl StatementsTranspiler { )) } TypedExprKind::If(cond, then_expr, else_expr) => { - // Conditional expressions: (cond ? then_expr : else_expr) - let c_cond = self.transpile_expr(cond)?; - let c_then = self.transpile_expr(then_expr)?; - let c_else = match else_expr { - Some(else_expr) => self.transpile_expr(else_expr)?, - None => return Err("If expressions must have an else branch".to_string()), - }; - Ok(CExpr::Ternary( - Box::new(c_cond), - Box::new(c_then), - Box::new(c_else), - )) - } - TypedExprKind::Assign(lhs, rhs) => { - // Assignments are expressions in C, so we can transpile them - let c_lhs = self.transpile_expr(lhs)?; - let c_rhs = self.transpile_expr(rhs)?; - Ok(CExpr::Assign(Box::new(c_lhs), Box::new(c_rhs))) + // Conditional expressions - for now, simplify to function call + // This is not ideal but works for basic cases + Err("Conditional expressions not yet supported".to_string()) } _ => Err(format!("Unsupported expression: {:?}", expr.kind)), } @@ -186,10 +171,18 @@ impl StatementsTranspiler { }; Ok(CStmt::Return(c_ret)) } - + TypedExprKind::If(cond, then_expr, else_expr) => { + let c_cond = self.transpile_expr(cond)?; + let then_stmts = self.expr_to_stmts(then_expr)?; + let else_stmts = match else_expr { + Some(else_expr) => Some(self.expr_to_stmts(else_expr)?), + None => None, + }; + Ok(CStmt::If(c_cond, then_stmts, else_stmts)) + } TypedExprKind::While(cond, body) => { let c_cond = self.transpile_expr(cond)?; - let body_stmts = self.expr_to_loop_stmts(body)?; + let body_stmts = self.expr_to_stmts(body)?; Ok(CStmt::While(c_cond, body_stmts)) } TypedExprKind::Do(exprs) => { @@ -233,7 +226,7 @@ impl StatementsTranspiler { let incr = CExpr::UnOp(CUnaryOp::PreInc, Box::new(CExpr::Var(var_name.clone()))); - let body_stmts = self.expr_to_loop_stmts(body)?; + let body_stmts = self.expr_to_stmts(body)?; Ok(CStmt::For(init, cond, incr, body_stmts)) } @@ -276,7 +269,7 @@ impl StatementsTranspiler { }); let mut body_stmts = vec![bind]; - body_stmts.extend(self.expr_to_loop_stmts(body)?); + body_stmts.extend(self.expr_to_stmts(body)?); Ok(CStmt::For(idx_decl, cond, incr, body_stmts)) } @@ -298,7 +291,7 @@ impl StatementsTranspiler { // tmp_arr = { ... } let (arr_name, arr_decl) = self.fresh_tmp_var( "_arr", - CType::Array(Box::new(elem_ty.clone())), + CType::Array(Box::new(elem_ty.clone()), arr_len), Some(CExpr::ArrayLit(c_elems)), ); @@ -325,7 +318,7 @@ impl StatementsTranspiler { }); let mut body_stmts = vec![bind]; - body_stmts.extend(self.expr_to_loop_stmts(body)?); + body_stmts.extend(self.expr_to_stmts(body)?); Ok(CStmt::Block(vec![ CStmt::VarDecl(arr_decl), @@ -389,35 +382,6 @@ impl StatementsTranspiler { } } - /// Convert expression to statements for loop bodies (no implicit return) - pub fn expr_to_loop_stmts(&mut self, expr: &TypedExpr) -> Result, String> { - match &expr.kind { - TypedExprKind::Do(stmts) => { - let mut c_stmts = Vec::new(); - let mut defers = Vec::new(); - for stmt in stmts { - match &stmt.kind { - TypedExprKind::Defer(defer_expr) => { - defers.push(self.transpile_stmt(defer_expr)?); - } - _ => { - c_stmts.push(self.transpile_stmt(stmt)?); - } - } - } - // Execute defers in reverse order at the end - for defer_stmt in defers.into_iter().rev() { - c_stmts.push(defer_stmt); - } - Ok(c_stmts) - } - _ => { - // For non-Do expressions in loops, just transpile as statement - Ok(vec![self.transpile_stmt(expr)?]) - } - } - } - fn binop_to_c_binop(&self, op: &BinOp) -> Result { match op { BinOp::Add => Ok(CBinaryOp::Add), @@ -454,13 +418,9 @@ impl StatementsTranspiler { Type::String => Ok(CType::Ptr(Box::new(CType::Char))), Type::Unit => Ok(CType::Void), Type::Ptr(inner) => Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?))), - Type::Array(inner) => { - let inner_type = self.type_to_ctype(inner)?; - // Arrays are pointers to the element type - Ok(CType::Ptr(Box::new(inner_type))) - } - 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::Array(inner) => Ok(CType::Ptr(Box::new(self.type_to_ctype(inner)?))), + Type::Struct(name, _) => Ok(CType::Struct(name.clone())), + Type::Enum(name, _) => Ok(CType::Struct(name.clone())), Type::Tuple(types) => { let mut fields = Vec::new(); for (i, inner_ty) in types.iter().enumerate() { @@ -502,7 +462,7 @@ impl StatementsTranspiler { TypeAnnot::Cons(name, args) if args.is_empty() => convert_to_c_type(name), TypeAnnot::Cons(name, _args) => { // Generic types - for now just use the base name - Ok(CType::Ptr(Box::new(CType::Struct(name.clone())))) + Ok(CType::Struct(name.clone())) } TypeAnnot::Ptr(inner) => { let inner_type = self.type_annot_to_ctype(inner)?; @@ -510,7 +470,6 @@ impl StatementsTranspiler { } TypeAnnot::Array(inner) => { let inner_type = self.type_annot_to_ctype(inner)?; - // Arrays are pointers to the element type Ok(CType::Ptr(Box::new(inner_type))) } TypeAnnot::Tuple(fields) => { diff --git a/src/codegen/transpiler.rs b/src/codegen/transpiler.rs index dae1960..dbb7855 100644 --- a/src/codegen/transpiler.rs +++ b/src/codegen/transpiler.rs @@ -2,69 +2,24 @@ use crate::ast::*; use crate::c_ir::*; use crate::c_lowerer::declaration_transpiler::DeclarationTranspiler; use crate::c_lowerer::statements_transpiler::StatementsTranspiler; - -/// Extract variable name from a declaration like "int x = 10" -fn extract_var_declaration(code: &str) -> Option { - // Pattern: type name = ... - let parts: Vec<&str> = code.split('=').collect(); - if parts.len() >= 2 { - let left = parts[0].trim(); - // Extract the variable name (last word before =) - if let Some(var_name) = left.split_whitespace().last() { - if !var_name.is_empty() { - return Some(var_name.to_string()); - } - } - } - None -} - -/// Extract variable name from an assignment like "x = y + 1" -fn extract_var_assignment(code: &str) -> Option { - // Pattern: name = ... - let parts: Vec<&str> = code.split('=').collect(); - if parts.len() >= 2 { - let left = parts[0].trim(); - // Check if it looks like a simple variable (no whitespace = simple type) - if !left.contains(' ') && !left.contains('*') && !left.contains('[') { - return Some(left.to_string()); - } - } - None -} +use std::collections::HashMap; pub struct Transpiler { - structs: Vec, // Changed from HashMap to preserve order + structs: HashMap, functions: Vec, globals: Vec, decl_transpiler: DeclarationTranspiler, stmt_transpiler: StatementsTranspiler, - array_types: std::collections::HashSet, // Track array types we need to generate - has_main: bool, // Track if we found a main function } impl Transpiler { pub fn new() -> Self { Transpiler { - structs: Vec::new(), + structs: HashMap::new(), functions: Vec::new(), globals: Vec::new(), decl_transpiler: DeclarationTranspiler::new(), stmt_transpiler: StatementsTranspiler::new(), - array_types: std::collections::HashSet::new(), - has_main: false, - } - } - - fn register_array_type(&mut self, elem_type: &CType) { - self.array_types - .insert(Self::get_array_struct_name(elem_type)); - } - - fn collect_array_types_from_ctype(&mut self, ty: &CType) { - match ty { - CType::Ptr(inner) => self.collect_array_types_from_ctype(inner), - _ => {} } } @@ -75,57 +30,17 @@ impl Transpiler { self.lower_function_bodies_to_c_ir(nodes)?; - // Rename main to suic_main and track that we have a main - if let Some(main_func) = self.functions.iter_mut().find(|f| f.name == "main") { - main_func.name = "suic_main".to_string(); - self.has_main = true; - } - // Generate C code let mut output = String::new(); // Add includes - output.push_str("#include \"../libsuicmez/libsuicmez.h\"\n"); output.push_str("#include \n"); output.push_str("#include \n"); output.push_str("#include \n"); output.push_str("#include \n"); - output.push_str("\n"); - - // GC functions - output.push_str("void* gc_suic_alloc(size_t size);\n"); - output.push_str("void suic_gc_free(void* ptr);\n"); - output.push_str("\n"); - - // Helper functions for heap allocation - output.push_str("// Helper for allocating arrays\n"); - output.push_str( - "static void* suic_alloc_array(size_t elem_size, size_t len, void* init_data) {\n", - ); - output.push_str(" void* ptr = gc_suic_alloc(elem_size * len);\n"); - output.push_str(" if (init_data) memcpy(ptr, init_data, elem_size * len);\n"); - output.push_str(" return ptr;\n"); - output.push_str("}\n"); - output.push_str("\n"); - - // Helper for allocating structs - output.push_str("// Helper for allocating structs\n"); - output.push_str("static void* suic_alloc_struct(size_t size, void* init_data) {\n"); - output.push_str(" void* ptr = gc_suic_alloc(size);\n"); - output.push_str(" if (init_data) memcpy(ptr, init_data, size);\n"); - output.push_str(" return ptr;\n"); - output.push_str("}\n"); - output.push_str("\n"); - - // Generate array wrapper structs for all array types used - for array_type_name in &self.array_types { - output.push_str(&self.generate_array_struct(array_type_name)); - output.push_str(";\n"); - } - output.push_str("\n"); // Generate struct declarations - for struct_decl in &self.structs { + for struct_decl in self.structs.values() { output.push_str(&self.generate_struct_decl(struct_decl)); output.push_str(";\n"); } @@ -150,12 +65,6 @@ impl Transpiler { output.push_str("\n"); } - // Generate wrapper main if we found a main function - if self.has_main { - output.push_str(&self.generate_wrapper_main()); - output.push_str("\n"); - } - Ok(output) } @@ -163,28 +72,16 @@ impl Transpiler { match &node.kind { TypedASTNodeKind::Struct(s) => { let struct_decl = self.decl_transpiler.transpile_struct(s)?; - // Collect array types from struct fields - for field in &struct_decl.fields { - self.collect_array_types_from_ctype(&field.ty); - } - self.structs.push(struct_decl); + self.structs.insert(s.name.clone(), struct_decl); } TypedASTNodeKind::Enum(e) => { let enum_structs = self.decl_transpiler.transpile_enum(e)?; for struct_decl in enum_structs { - for field in &struct_decl.fields { - self.collect_array_types_from_ctype(&field.ty); - } - self.structs.push(struct_decl); + self.structs.insert(struct_decl.name.clone(), struct_decl); } } TypedASTNodeKind::Function(f) => { let mut func_decl = self.decl_transpiler.transpile_function(f)?; - // Collect array types from function signature - self.collect_array_types_from_ctype(&func_decl.return_type); - for param in &func_decl.params { - self.collect_array_types_from_ctype(¶m.ty); - } // Body will be filled later func_decl.body = Some(Vec::new()); self.functions.push(func_decl); @@ -192,10 +89,6 @@ impl Transpiler { TypedASTNodeKind::Impl(imp) => { for method in &imp.methods { let mut func_decl = self.decl_transpiler.transpile_function(method)?; - self.collect_array_types_from_ctype(&func_decl.return_type); - for param in &func_decl.params { - self.collect_array_types_from_ctype(¶m.ty); - } func_decl.name = format!("{}_{}", imp.target, method.name); func_decl.body = Some(Vec::new()); self.functions.push(func_decl); @@ -240,22 +133,6 @@ impl Transpiler { Ok(()) } - fn generate_array_struct(&self, array_type_name: &str) -> String { - let mut output = format!("struct {} {{\n", array_type_name); - output.push_str(" void* data;\n"); - output.push_str(" size_t len;\n"); - output.push_str(" size_t capacity;\n"); - output.push_str("}"); - output - } - - fn get_array_struct_name(elem_type: &CType) -> String { - format!( - "sui_array_{}", - elem_type.to_string().replace(" ", "_").replace("*", "ptr") - ) - } - fn generate_struct_decl(&self, struct_decl: &CStructDecl) -> String { let mut output = format!("struct {} {{\n", struct_decl.name); for field in &struct_decl.fields { @@ -297,19 +174,6 @@ impl Transpiler { output } - fn generate_wrapper_main(&self) -> String { - let mut output = String::new(); - output.push_str("int main(int argc, char* argv[]) {\n"); - output.push_str(" // init gc and stuff\n"); - output.push_str(" // init globals\n"); - output.push_str(" // init event loop\n"); - output.push_str(" int result = suic_main();\n"); - output.push_str(" // free the stuff\n"); - output.push_str(" return result;\n"); - output.push_str("}\n"); - output - } - fn generate_var_decl(&self, var: &CVarDecl) -> String { let mut output = format!("{} {}", var.ty.to_string(), var.name); if let Some(init) = &var.initializer { @@ -318,67 +182,8 @@ impl Transpiler { output } - fn generate_heap_alloc(&self, ty: &CType) -> String { - match ty { - CType::Struct(name) => { - format!("(struct {}*)suic_gc_alloc(sizeof(struct {}))", name, name) - } - CType::Array(elem_type) => { - format!( - "(struct {}*)suic_gc_alloc(sizeof(struct {}))", - Self::get_array_struct_name(elem_type), - Self::get_array_struct_name(elem_type) - ) - } - _ => "NULL".to_string(), - } - } - - fn add_debug_print(&self, code: &str) -> String { - // Extract the actual statement for the debug message - let trimmed = code.trim_end_matches('\n').trim_start(); - let trimmed_no_semi = trimmed.trim_end_matches(';'); - - if trimmed_no_semi.is_empty() { - return code.to_string(); - } - - let mut result = code.trim_end_matches('\n').to_string(); - result.push('\n'); - - // Escape quotes in the output - let escaped_code = trimmed_no_semi.replace("\"", "\\\""); - - // Try to extract variable name and format for printing - if let Some(var_name) = extract_var_declaration(trimmed_no_semi) { - // For declarations, determine the format specifier - let format_spec = if trimmed_no_semi.contains("char*") { - "%s" - } else if trimmed_no_semi.contains("float") { - "%f" - } else if trimmed_no_semi.contains("*") { - "%p" // pointer - } else { - "%d" - }; - result.push_str(&format!( - " printf(\"| {} | \\n {}\\n\", {});\n", - escaped_code, format_spec, var_name - )); - } else if let Some(var_name) = extract_var_assignment(trimmed_no_semi) { - result.push_str(&format!( - " printf(\"| {} | \\n %d\\n\", {});\n", - escaped_code, var_name - )); - } else { - result.push_str(&format!(" printf(\"| {} |\\n\");\n", escaped_code)); - } - - result - } - fn generate_stmt(&self, stmt: &CStmt) -> String { - let code = match stmt { + match stmt { CStmt::VarDecl(var) => format!(" {};\n", self.generate_var_decl(var)), CStmt::Expr(expr) => format!(" {};\n", self.generate_expr(expr)), CStmt::Assign(lhs, rhs) => format!( @@ -436,13 +241,6 @@ impl Transpiler { } CStmt::Break => "break;\n".to_string(), CStmt::Continue => "continue;\n".to_string(), - }; - - // Add debug print for simple statements only (not control flow) - match stmt { - CStmt::VarDecl(_) | CStmt::Expr(_) | CStmt::Assign(_, _) => self.add_debug_print(&code), - CStmt::Return(_) => code, // Don't add debug print to return statements to avoid unreachable code - _ => code, // Control flow statements don't get debug prints } } @@ -451,13 +249,7 @@ impl Transpiler { CExpr::IntLit(i) => format!("{}", i), CExpr::FloatLit(f) => format!("{:.6}", f), CExpr::BoolLit(b) => format!("{}", b), - CExpr::StringLit(s) => { - format!( - "suic_alloc_array(sizeof(char), {}, \"{}\")", - s.len() + 1, // +1 for null terminator - s - ) - } + CExpr::StringLit(s) => format!("\"{}\"", s), CExpr::Var(name) => name.clone(), CExpr::Call(func, args) => { let args_str = args @@ -465,51 +257,7 @@ impl Transpiler { .map(|arg| self.generate_expr(arg)) .collect::>() .join(", "); - - // Map Sui function names to C function names for built-ins - let c_func_name = match func.as_str() { - "ode_init" => "suic_ode_init", - "ode_close" => "suic_ode_close", - "ode_world_create" => "suic_ode_world_create", - "ode_world_destroy" => "suic_ode_world_destroy", - "ode_world_set_gravity" => "suic_ode_world_set_gravity", - "ode_world_step" => "suic_ode_world_step", - "ode_body_create" => "suic_ode_body_create", - "ode_body_destroy" => "suic_ode_body_destroy", - "ode_body_set_position" => "suic_ode_body_set_position", - "ode_body_set_linear_vel" => "suic_ode_body_set_linear_vel", - "ode_body_set_box_mass" => "suic_ode_body_set_box_mass", - "ode_create_box_geom" => "suic_ode_create_box_geom", - "ode_geom_set_body" => "suic_ode_geom_set_body", - "ode_geom_destroy" => "suic_ode_geom_destroy", - "ode_simple_space_create" => "suic_ode_simple_space_create", - "ode_space_destroy" => "suic_ode_space_destroy", - "ode_create_plane_geom" => "suic_ode_create_plane_geom", - "ode_body_get_position" => "suic_ode_body_get_position", - "ode_space_collide" => "suic_ode_space_collide", - "ode_joint_group_create" => "suic_ode_joint_group_create", - "ode_joint_group_destroy" => "suic_ode_joint_group_destroy", - "ode_joint_group_empty" => "suic_ode_joint_group_empty", - "ode_body_get_linear_vel" => "suic_ode_body_get_linear_vel", - "ode_body_get_rotation" => "suic_ode_body_get_rotation", - "ode_body_set_rotation" => "suic_ode_body_set_rotation", - // Raylib functions - "init_window" => "suic_init_window", - "close_window" => "suic_close_window", - "window_should_close" => "suic_window_should_close", - "set_target_fps" => "suic_set_target_fps", - "begin_drawing" => "suic_begin_drawing", - "end_drawing" => "suic_end_drawing", - "clear_background" => "suic_clear_background", - "begin_mode3d" => "suic_begin_mode3d", - "end_mode3d" => "suic_end_mode3d", - "draw_cube" => "suic_draw_cube", - "draw_cube_wires" => "suic_draw_cube_wires", - "is_key_down" => "suic_is_key_down", - _ => func, - }; - - format!("{}({})", c_func_name, args_str) + format!("{}({})", func, args_str) } CExpr::BinOp(lhs, op, rhs) => { format!( @@ -527,7 +275,7 @@ impl Transpiler { } CExpr::AddrOf(expr) => format!("&{}", self.generate_expr(expr)), CExpr::Deref(expr) => format!("*{}", self.generate_expr(expr)), - CExpr::Dot(expr, field) => format!("(*{}).{}", self.generate_expr(expr), field), + CExpr::Dot(expr, field) => format!("{}.{}", self.generate_expr(expr), field), CExpr::Index(array, index) => format!( "{}[{}]", self.generate_expr(array), @@ -538,12 +286,7 @@ impl Transpiler { .iter() .map(|(name, expr)| format!(".{} = {}", name, self.generate_expr(expr))) .collect(); - format!( - "suic_alloc_struct(sizeof(struct {}), &(struct {}){{ {} }})", - struct_name, - struct_name, - field_inits.join(", ") - ) + format!("(struct {}){{ {} }}", struct_name, field_inits.join(", ")) } CExpr::EnumLit(enum_name, variant_name, args) => { // Find the variant index - for simplicity, assume variants are in order @@ -554,7 +297,7 @@ impl Transpiler { let union_field_name = variant_name.to_lowercase(); let struct_init = if args.is_empty() { - "".to_string() + "{}".to_string() } else { let field_inits: Vec = args .iter() @@ -564,48 +307,19 @@ impl Transpiler { format!("{{ {} }}", field_inits.join(", ")) }; - let variant_init = if struct_init.is_empty() { - format!("(struct {}){{}}", variant_struct_name) - } else { - format!("(struct {}){}", variant_struct_name, struct_init) - }; - format!( - "suic_alloc_struct(sizeof(struct {}), &(struct {}){{ .discriminant = {}, .data = {{ .{} = {} }} }})", - enum_name, enum_name, variant_index, union_field_name, variant_init + "({}){{ .discriminant = {}, .data = {{ .{} = ({}{}) }} }}", + enum_name, variant_index, union_field_name, variant_struct_name, struct_init ) } CExpr::ArrayLit(array_lit) => { - if array_lit.is_empty() { - "NULL".to_string() - } else { - let vec: Vec = array_lit - .iter() - .map(|expr| self.generate_expr(expr)) - .collect(); - // Generate heap-allocated array using helper function - format!( - "suic_alloc_array(sizeof(int), {}, (int[]){{{}}})", - vec.len(), - vec.join(", ") - ) - } - } - CExpr::Assign(lhs, rhs) => { - format!( - "({} = {})", - self.generate_expr(lhs), - self.generate_expr(rhs) - ) - } - CExpr::Ternary(cond, then_expr, else_expr) => { - format!( - "({} ? {} : {})", - self.generate_expr(cond), - self.generate_expr(then_expr), - self.generate_expr(else_expr) - ) + let vec = array_lit + .iter() + .map(|expr| self.generate_expr(expr)) + .collect::>(); + let len = vec.len(); + format!("{}[{}]{{ {} }}", vec[0], len, vec.join(", ")) } } } diff --git a/src/main.rs b/src/main.rs index 7d454da..d2317ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,42 +1,40 @@ -use clap::Parser; -use std::fs; -use suicmez::{ - codegen::transpiler::Transpiler, - import_resolver::ImportResolver, - lambda_lower::LambdaLowerer, - monomorphize::{Monomorphizer, check_no_typevars}, - typechecker::TypeChecker, -}; + use clap::Parser; + use std::fs; + use suicmez::{ + codegen::transpiler::Transpiler, + import_resolver::ImportResolver, + lambda_lower::LambdaLowerer, + monomorphize::{Monomorphizer, check_no_typevars}, + typechecker::TypeChecker, + }; -#[derive(Parser)] -#[command(author, version, about = "A compiler for the Sui language")] -struct Args { - /// Run the test suite instead of compiling a file - #[arg(short, long)] - test: bool, + #[derive(Parser)] + #[command(author, version, about = "A compiler for the Sui language")] + struct Args { + /// Run the test suite instead of compiling a file + #[arg(short, long)] + test: bool, - /// The Sui source file to compile - file: Option, -} + /// The Sui source file to compile + file: Option, + } -fn main() { - let args = Args::parse(); + fn main() { + let args = Args::parse(); - if args.test { - run_test_suite(); - } else if let Some(filename) = args.file { - println!("Type checking file: {}", filename); + if args.test { + run_test_suite(); + } else if let Some(filename) = args.file { + println!("Type checking file: {}", filename); - if let Err(e) = run_file(&filename) { - eprintln!("Error: {}", e); - } - } else { - eprintln!( - "No file specified. Use --test to run the test suite or provide a Sui file to compile." - ); - std::process::exit(1); - } -} + if let Err(e) = run_file(&filename) { + eprintln!("Error: {}", e); + } + } else { + eprintln!("No file specified. Use --test to run the test suite or provide a Sui file to compile."); + std::process::exit(1); + } + } fn run_test_suite() { println!("Running test suite...\n"); @@ -183,11 +181,8 @@ fn run_file(filename: &str) -> Result<(), String> { .resolve(filename) .map_err(|e| format!("Import resolution error: {}", e))?; - println!( - "Import resolution complete! {} total nodes loaded", - ast_nodes.len() - ); - + println!("Import resolution complete! {} total nodes loaded", ast_nodes.len()); + // Read the source file for error reporting let source = fs::read_to_string(filename) .map_err(|e| format!("Error reading file {}: {}", filename, e))?; diff --git a/src/monomorphize.rs b/src/monomorphize.rs index fb6c6ac..f97a196 100644 --- a/src/monomorphize.rs +++ b/src/monomorphize.rs @@ -366,12 +366,7 @@ impl Monomorphizer { if !field_types.is_empty() { self.infer_struct_specialization(name, &field_types, &mut needs); } - let new_kind = TypedExprKind::StructLit(name.clone(), new_fields); - let mut temp_expr = expr.clone(); - temp_expr.kind = new_kind.clone(); - // Collect specialization needs from the struct literal's type - self.collect_needs_from_expr_type(&temp_expr, &mut needs); - new_kind + TypedExprKind::StructLit(name.clone(), new_fields) } TypedExprKind::EnumLit(enum_name, variant, args) => { diff --git a/src/typechecker.rs b/src/typechecker.rs index 2dccee6..9e7481e 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -351,9 +351,6 @@ impl TypeChecker { self.collect_definitions(node)?; } - // Add built-in functions - self.add_builtin_functions(); - // Second pass: typecheck everything self.env.enter_scope(); let mut typed_nodes = Vec::new(); @@ -365,424 +362,6 @@ impl TypeChecker { Ok(typed_nodes) } - fn add_builtin_functions(&mut self) { - // ODE Physics Engine functions - self.env.functions.insert( - "ode_init".to_string(), - FunctionType { - type_params: vec![], - params: vec![], - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_close".to_string(), - FunctionType { - type_params: vec![], - params: vec![], - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_world_create".to_string(), - FunctionType { - type_params: vec![], - params: vec![], - return_type: Type::Ptr(Box::new(Type::Unit)), // opaque pointer - }, - ); - self.env.functions.insert( - "ode_world_destroy".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Ptr(Box::new(Type::Unit))], - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_world_set_gravity".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Float, - Type::Float, - Type::Float, - ], // world_id, x, y, z - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_world_step".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Ptr(Box::new(Type::Unit)), Type::Float], - return_type: Type::Unit, - }, - ); - - // Body management - self.env.functions.insert( - "ode_body_create".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Ptr(Box::new(Type::Unit))], // world - return_type: Type::Ptr(Box::new(Type::Unit)), // body - }, - ); - self.env.functions.insert( - "ode_body_destroy".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Ptr(Box::new(Type::Unit))], // body - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_body_set_position".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Float, - Type::Float, - Type::Float, - ], // body, x, y, z - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_body_set_linear_vel".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Float, - Type::Float, - Type::Float, - ], // body, x, y, z - return_type: Type::Unit, - }, - ); - - // Geometry and mass - self.env.functions.insert( - "ode_body_set_box_mass".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Float, - Type::Float, - Type::Float, - Type::Float, - ], // body, density, lx, ly, lz - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_create_box_geom".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Float, - Type::Float, - Type::Float, - ], // space, lx, ly, lz - return_type: Type::Ptr(Box::new(Type::Unit)), // geom - }, - ); - self.env.functions.insert( - "ode_create_plane_geom".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Float, - Type::Float, - Type::Float, - Type::Float, - ], // space, a, b, c, d - return_type: Type::Ptr(Box::new(Type::Unit)), // geom - }, - ); - self.env.functions.insert( - "ode_geom_set_body".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Ptr(Box::new(Type::Unit)), - ], // geom, body - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_geom_destroy".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Ptr(Box::new(Type::Unit))], // geom - return_type: Type::Unit, - }, - ); - - // Collision space - self.env.functions.insert( - "ode_simple_space_create".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Ptr(Box::new(Type::Unit))], // parent space (can be null) - return_type: Type::Ptr(Box::new(Type::Unit)), // space - }, - ); - self.env.functions.insert( - "ode_space_destroy".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Ptr(Box::new(Type::Unit))], // space - return_type: Type::Unit, - }, - ); - - // Collision detection and contact joints - self.env.functions.insert( - "ode_space_collide".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Ptr(Box::new(Type::Unit)), - Type::Ptr(Box::new(Type::Unit)), - ], // world, space, contactgroup - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_joint_group_create".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Int], // max_size - return_type: Type::Ptr(Box::new(Type::Unit)), // contactgroup - }, - ); - self.env.functions.insert( - "ode_joint_group_destroy".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Ptr(Box::new(Type::Unit))], // group - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_joint_group_empty".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Ptr(Box::new(Type::Unit))], // group - return_type: Type::Unit, - }, - ); - - // Additional body functions - self.env.functions.insert( - "ode_body_get_linear_vel".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Ptr(Box::new(Type::Float)), - Type::Ptr(Box::new(Type::Float)), - Type::Ptr(Box::new(Type::Float)), - ], // body, x, y, z - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_body_get_rotation".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Ptr(Box::new(Type::Float)), - Type::Ptr(Box::new(Type::Float)), - Type::Ptr(Box::new(Type::Float)), - Type::Ptr(Box::new(Type::Float)), - ], // body, w, x, y, z - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "ode_body_set_rotation".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Float, - Type::Float, - Type::Float, - Type::Float, - ], // body, w, x, y, z - return_type: Type::Unit, - }, - ); - - // Raylib functions - // Window management - self.env.functions.insert( - "init_window".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Int, Type::Int, Type::String], // width, height, title - return_type: Type::Bool, - }, - ); - 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], // fps - return_type: Type::Unit, - }, - ); - - // Drawing - 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], // r, g, b, a - return_type: Type::Unit, - }, - ); - - // 3D Mode - self.env.functions.insert( - "begin_mode3d".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Int, - ], // pos_x,y,z target_x,y,z up_x,y,z fovy projection - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "end_mode3d".to_string(), - FunctionType { - type_params: vec![], - params: vec![], - return_type: Type::Unit, - }, - ); - - // 3D Drawing - self.env.functions.insert( - "draw_cube".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Int, - Type::Int, - Type::Int, - Type::Int, - ], // x,y,z width,height,length r,g,b,a - return_type: Type::Unit, - }, - ); - self.env.functions.insert( - "draw_cube_wires".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Float, - Type::Int, - Type::Int, - Type::Int, - Type::Int, - ], // x,y,z width,height,length r,g,b,a - return_type: Type::Unit, - }, - ); - - // Input - self.env.functions.insert( - "is_key_down".to_string(), - FunctionType { - type_params: vec![], - params: vec![Type::Int], // key - return_type: Type::Bool, - }, - ); - - // Physics integration helper - self.env.functions.insert( - "ode_body_get_position".to_string(), - FunctionType { - type_params: vec![], - params: vec![ - Type::Ptr(Box::new(Type::Unit)), - Type::Ptr(Box::new(Type::Float)), - Type::Ptr(Box::new(Type::Float)), - Type::Ptr(Box::new(Type::Float)), - ], // body, x, y, z - return_type: Type::Unit, - }, - ); - } - fn collect_definitions(&mut self, node: &ASTNode) -> Result<(), TypeError> { match &node.kind { ASTNodeKind::Struct(s) => { diff --git a/syntax_test.sui b/syntax_test.sui new file mode 100644 index 0000000..0db6f6a --- /dev/null +++ b/syntax_test.sui @@ -0,0 +1,448 @@ +use "std/abc" +load "math.so" as math_lib + +extern print(msg: string) -> int from libc # this is a comment +extern malloc(size: int) -> int from libc #* this is a comment too *# +extern add_numbers(a: int, b: int) -> int from math_lib + +# this is a funny comment +struct Point + x: int, + y: int +end + +struct Generic + value: T, + tag: string +end + +struct Complex + first: T, + second: U +end + +struct EmptyStruct +end + +struct ArrayStruct + numbers: [int], + matrix: [[float]] +end + +enum Option + Some(T), + None +end + +enum Result + Ok(T), + Err(E) +end + +enum Status + Active, + Inactive, + Pending(string) +end + +enum Tree + Leaf(T), + Branch(T, T) +end + +trait Show + fn display(msg: string) -> string, + fn to_string() -> string +end + +trait Comparable + fn compare(other: T) -> int +end + +trait Container + fn push(item: T) -> int, + fn pop() -> T +end + +impl Point + fn new(x: int, y: int) -> Point + Point { x: x, y: y } + + fn distance() -> float do + let x_sq = 5 * 5 + let y_sq = 3 * 3 + ((x_sq + y_sq) as float) + end + + fn move_by(dx: int, dy: int) -> Point do + let new_x = 5 + 10 + let new_y = 3 + 20 + Point { x: new_x, y: new_y } + end +end + +impl Option : Show + fn display(msg: string) -> string + "Option value" + + fn to_string() -> string + "option" +end + +impl Result + fn is_ok() -> bool + true + + fn unwrap() -> string + "unwrapped" +end + + +fn greet(name: string) -> string + "Hello, " + name + +fn get_answer() -> int + 42 + +fn print_number(num: int) + num + +fn add(a: int, b: int) -> int + a + b + +fn identity(value: T) -> T + value + +fn pair(first: T, second: U) -> (T, U) + (first, second) + +fn array_func(arr: [int]) -> [int] + arr + +fn process(item: T) -> string + "processed" + +fn process_list(items: int) -> int do + let result = 0 + result + items +end + +fn literals() -> bool do + let int_val = 42 + let float_val = 3.14 + let negative = -100 + let scientific = 1.5e-10 + let bool_true = true + let bool_false = false + let string_val = "hello world" + let empty_string = "" + true +end + +fn collections() -> bool do + let arr = [1, 2, 3, 4, 5] + let empty_arr = [] + let tuple = (1, "hello", 3.14) + let single_tuple = (42) + true +end + +fn struct_enum_literals() -> bool do + let point = Point { x: 10, y: 20 } + let option_val = Option::Some(42) + let option_none = Option::None + let result_ok = Result::Ok("success") + let result_err = Result::Err(404) + let status = Status::Pending("loading...") + true +end + +fn arithmetic_logic() -> int do + let a = 10 + let b = 5 + let add_result = a + b + let sub_result = a - b + let mul_result = a * b + let div_result = a / b + let mod_result = a % b + + let and_result = true and false + let or_result = true or false + let not_result = not true + + let eq = a == b + let neq = a != b + let lt = a < b + let gt = a > b + let leq = a <= b + let geq = a >= b + + add_result + sub_result +end + + +fn unary() -> int do + let a = 5 + let neg = -a + let b = true + let not_b = not b + a + 1 +end + + +fn bindings() -> int do + let x = 10 + let mut y = 20 + let uniq z = 30 + let once w = 40 + + let typed: int = 100 + let mut_typed: string = "hello" + + x + 5 +end + + +fn if_else(n: int) -> int + if n > 0 + 100 + else + -100 + +fn if_else_complex(a: int, b: int) -> string + if a > b + "a is greater" + else + if a == b + "equal" + else + "b is greater" + + +fn match_simple(opt: Option) -> int + match opt + Option::Some(x) => x, + Option::None => 0 + end + +fn match_complex(val: int) -> string + match val + 0 => "zero", + 1 => "one", + 2 => "two", + _ => "many" + end + +fn match_pattern(p: Point) -> string + match p + Point { x: 0, y: 0 } => "origin", + Point { x: x, y: y } => "point" + end + + +fn while_loop(n: int) -> int do + let mut count = 0 + while count < n + do + count = count + 1 + end +end + + +fn do_block() -> int + do + let a = 10 + let b = 20 + let c = 30 + a + b + c + end + +fn nested_do() -> int + do + let x = do + 5 + end + let y = do + 10 + end + x + y + end + + +fn function_calls() -> int do + let point = Point { x: 5, y: 10 } + let x_coord = point.x + let arr = [1, 2, 3] + let first = arr[0] + + let result = add(10, 20) + let identity_val = identity(42) + + result + first +end + + +fn optional_chain(opt: Option) -> int do + let val = opt?.x + 100 +end + + +fn early_return() -> int do + let opt = Option::Some(42) + let val = opt? + val +end + + +fn casting() -> float do + let int_val = 42 + let float_val = (int_val as float) + let x = (100 as float) + 3.14 + x +end + +fn lambda_example() -> int do + let add_one = lambda (x) x + 1 + let multiply = lambda (x, y) x * y + let get_five = lambda () 5 + + let applied = add_one(10) + applied +end + +fn assignment() -> int do + let mut x = 10 + x = 20 + x = x + 5 + x +end + +fn with_return(n: int) -> int do + if n < 0 + return -1 + n + 100 +end + +fn with_break() -> int do + let mut i = 0 + while i < 10 + do + if i == 5 + break + i = i + 1 + end + i +end + +fn with_continue() -> int do + let mut sum = 0 + let mut i = 0 + while i < 10 + do + i = i + 1 + if i % 2 == 0 + continue + sum = sum + i + end + sum +end + + +@deprecated("use new_func instead") +fn old_func() -> int + 42 + +@optimize(level = aggressive) +fn fast_func() -> int + 100 + +@test +fn test_something() -> bool + true + +fn fibonacci(n: int) -> int + if n <= 1 + n + else + fibonacci(n - 1) + fibonacci(n - 2) + +fn factorial(n: int) -> int do + let mut result = 1 + let mut i = 2 + while i <= n + do + result = result * i + i = i + 1 + end + result +end + +fn map_over_option(opt: Option) -> Option + match opt + Option::Some(x) => Option::Some(x), + Option::None => Option::None + end + +fn process_result(res: Result) -> int + match res + Result::Ok(x) => 1, + Result::Err(e) => 0 + end + +struct LinkedList + value: T, + next: Option +end + +impl LinkedList + fn new(v: int) -> LinkedList + LinkedList { value: 42, next: Option::None } + + fn head() -> int + 100 + + fn tail() -> Option + Option::None + + fn sum() -> int + do + let mut total = 0 + total + end +end + +fn complex_pattern_match(val: int) -> string + match val + 0 => "zero", + 1 => "one", + 2 => "two", + 3 => "three", + 4 => "four", + 5 => "five", + _ => "many" + end + +fn tuple_destructure() -> int do + let tup = (10, 20, 30) + 30 +end + +fn array_ops() -> int do + let arr = [1, 2, 3, 4, 5] + let first = arr[0] + let length = 5 + first + length +end + +fn range_example() -> int do + let r = 1..10 + 5 +end + +fn for_loop_example() -> int do + let sum = 0 + for i in 0..5 + sum + i + sum +end diff --git a/test_affine.sui b/test_affine.sui new file mode 100644 index 0000000..fdb5645 --- /dev/null +++ b/test_affine.sui @@ -0,0 +1,5 @@ +fn test_affine() -> int do + let uniq x = 5 + x + 1 + x + 2 +end \ No newline at end of file diff --git a/test_binding.sui b/test_binding.sui new file mode 100644 index 0000000..8761b1d --- /dev/null +++ b/test_binding.sui @@ -0,0 +1,5 @@ +fn test_binding_id() -> int do + let x = 5 + let x = x + 1 # shadowing + x +end \ No newline at end of file diff --git a/test_linear.sui b/test_linear.sui new file mode 100644 index 0000000..c663c16 --- /dev/null +++ b/test_linear.sui @@ -0,0 +1,4 @@ +fn test_linear() -> int do + let once y = 10 + 5 +end \ No newline at end of file diff --git a/test_linear_ok.sui b/test_linear_ok.sui new file mode 100644 index 0000000..c96a794 --- /dev/null +++ b/test_linear_ok.sui @@ -0,0 +1,4 @@ +fn test_linear_ok() -> int do + let once z = 10 + z + 5 +end \ No newline at end of file diff --git a/test_scoping.sui b/test_scoping.sui new file mode 100644 index 0000000..f06fc52 --- /dev/null +++ b/test_scoping.sui @@ -0,0 +1,11 @@ +fn test_scoping() -> int do + let x = 5 + let f = lambda (y) y + 1 # simple lambda + # f = lambda (z) z+1 + let x = 10 # shadow x + f(3) # should work +end + +fn stuff(f: fn(int, int) -> int, v: int) -> int do + f(v, v) +end diff --git a/test_shadow.sui b/test_shadow.sui new file mode 100644 index 0000000..ffbb6ac --- /dev/null +++ b/test_shadow.sui @@ -0,0 +1,5 @@ +fn test_shadow() -> int do + let x = 5 + let x = 10 + x +end \ No newline at end of file diff --git a/tests/basic_types.c b/tests/basic_types.c new file mode 100644 index 0000000..a916271 --- /dev/null +++ b/tests/basic_types.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include +int main(void); + + +int main(void) { + int x = 5; + float y = 10.500000; + bool z = true; + char* s = "hello"; + return x; +} + diff --git a/tests/codegen/INDEX.md b/tests/codegen/INDEX.md deleted file mode 100644 index 1d04a23..0000000 --- a/tests/codegen/INDEX.md +++ /dev/null @@ -1,136 +0,0 @@ -# Codegen Tests Index - -Quick reference guide for all codegen tests. - -## šŸ“‹ Test Overview - -| Test | Type | Features | Lines | -|------|------|----------|-------| -| `test_executable` | Basic | Integer math, functions | 4 | -| `test_array_simple` | Arrays | Literals, indexing, pointers | 4 | -| `test_enum_simple` | Enums | Variants, discriminant | 2 | -| `test_comprehensive` | Mixed | All basic types, structs | 18 | -| `test_all_types` | Coverage | Complete type test | 16 | - -## šŸš€ Quick Commands - -### Generate C from all tests -```bash -for f in tests/codegen/*.sui; do - ./target/debug/suicmez "$f" -done -``` - -### Compile all tests -```bash -for f in tests/codegen/*.c; do - gcc "$f" -o "/tmp/$(basename ${f%.c})" -done -``` - -### Run all tests -```bash -for exe in /tmp/test_*; do - echo "=== $(basename $exe) ===" - "$exe" 2>&1 -done -``` - -### Run single test -```bash -./target/debug/suicmez tests/codegen/test_comprehensive.sui -gcc tests/codegen/test_comprehensive.c -o /tmp/test -/tmp/test -``` - -## šŸ“– Documentation Files - -- **README.md** - Full documentation of all tests -- **TESTING.md** - How to run and debug tests -- **SUMMARY.md** - Organization and cleanup summary -- **INDEX.md** - This file - -## šŸŽÆ Test Selection Guide - -**I want to test:** - -- **Simple execution** → Use `test_executable` -- **Arrays** → Use `test_array_simple` -- **Enums** → Use `test_enum_simple` -- **Everything together** → Use `test_comprehensive` -- **All types** → Use `test_all_types` - -## āœ… Verification Checklist - -Before pushing: -- [ ] All `.sui` files transpile: `for f in tests/codegen/*.sui; do suicmez "$f" > /dev/null; done` -- [ ] All `.c` files compile: `for f in tests/codegen/*.c; do gcc "$f" -c; done` -- [ ] All tests execute: `for f in tests/codegen/*.c; do gcc "$f" -o /tmp/t && /tmp/t > /dev/null; done` -- [ ] Debug output works: `gcc tests/codegen/test_comprehensive.c -o /tmp/t && /tmp/t | head -3` - -## šŸ”§ Debug Features - -Each test includes debug output: -``` -| | - -``` - -Example: -``` -| int x = 10 | - 10 -``` - -Format specifiers are automatic: -- `%d` - integers -- `%f` - floats -- `%s` - strings -- `%p` - pointers - -## šŸ“¦ File Organization - -``` -tests/codegen/ -ā”œā”€ā”€ test_executable.sui ← Source -ā”œā”€ā”€ test_executable.c ← Generated -ā”œā”€ā”€ test_array_simple.sui -ā”œā”€ā”€ test_array_simple.c -ā”œā”€ā”€ test_enum_simple.sui -ā”œā”€ā”€ test_enum_simple.c -ā”œā”€ā”€ test_comprehensive.sui -ā”œā”€ā”€ test_comprehensive.c -ā”œā”€ā”€ test_all_types.sui -ā”œā”€ā”€ test_all_types.c -ā”œā”€ā”€ README.md ← Documentation -ā”œā”€ā”€ TESTING.md -ā”œā”€ā”€ SUMMARY.md -└── INDEX.md ← This file -``` - -Each `.sui` file has a corresponding `.c` file containing the generated C code with debug output. - -## šŸŽ“ Learning Path - -1. Start with `test_executable` - understand basic code generation -2. Move to `test_array_simple` - learn array handling -3. Check `test_enum_simple` - understand enum codegen -4. Study `test_comprehensive` - see everything together -5. Review `test_all_types` - verify complete coverage - -## šŸ’” Tips - -- Look at generated `.c` files to understand transpilation -- Run tests with output redirection: `./test 2>&1 | less` -- Compare `.sui` and `.c` files side by side -- Check debug output for execution trace -- Modify `.sui` files to experiment with codegen - -## šŸ“ž Getting Help - -See **TESTING.md** for: -- Common issues and solutions -- Compilation troubleshooting -- Debug output interpretation -- Verification procedures - diff --git a/tests/codegen/README.md b/tests/codegen/README.md deleted file mode 100644 index dc6b45b..0000000 --- a/tests/codegen/README.md +++ /dev/null @@ -1,201 +0,0 @@ -# Codegen Tests - -This directory contains test cases for the suicmez compiler's code generation (codegen) phase. Each test demonstrates different language features and their corresponding C output. - -## Test Files - -### Basic Tests - -#### `test_executable.sui` / `test_executable.c` -**Purpose:** Simple executable test with basic integer arithmetic -**Features:** -- Basic function definitions -- Integer variables and operations -- Return statements - -**Run:** -```bash -suicmez tests/codegen/test_executable.sui -gcc tests/codegen/test_executable.c -o test_executable -./test_executable -``` - -#### `test_array_simple.sui` / `test_array_simple.c` -**Purpose:** Test heap-allocated arrays with indexing -**Features:** -- Array literals: `[1, 2, 3]` -- Array indexing: `arr[0]` -- Arrays as pointers: `int*` -- C99 compound literals for array initialization - -**Output:** -``` -| int* arr = (int[]){1, 2, 3} | - 0x... -| int x = arr[0] | - 1 -``` - -#### `test_enum_simple.sui` / `test_enum_simple.c` -**Purpose:** Test enum types with discriminant + union pattern -**Features:** -- Enum variants -- Discriminant field for pattern matching -- Union-based storage for variant data -- Proper struct ordering - -**Generated Structures:** -```c -struct Color_Red { }; -struct Color_Green { }; -struct Color_Blue { }; -struct Color_union { - struct Color_Red red; - struct Color_Green green; - struct Color_Blue blue; -}; -struct Color { - int discriminant; - struct Color_union data; -}; -``` - -### Comprehensive Tests - -#### `test_comprehensive.sui` / `test_comprehensive.c` -**Purpose:** Combined test of all major features -**Features:** -- Stack-allocated types: `int`, `float`, `bool` -- Heap-allocated types: arrays, strings -- Struct instantiation and field access -- Enum creation and initialization -- Function calls with multiple parameters -- Complex expressions - -**Demonstrates:** -- Proper memory management distinctions -- Type conversions and initializations -- Debug output for each statement - -**Run:** -```bash -suicmez tests/codegen/test_comprehensive.sui -gcc tests/codegen/test_comprehensive.c -o test_comprehensive -./test_comprehensive -``` - -**Sample Output:** -``` -| int x = 10 | - 10 -| int y = 20 | - 20 -| int sum = add(x, y) | - 30 -| struct Point p = (struct Point){ .x = 5, .y = 15 } | - 5 -| int* arr = (int[]){1, 2, 3, 4, 5} | - 0x7ffd6d57d0b0 -| int first = arr[0] | - 1 -| char* msg = "hello" | - hello -``` - -#### `test_all_types.sui` / `test_all_types.c` -**Purpose:** Exhaustive test of all language types -**Features:** -- All primitive types: `int`, `float`, `bool` -- Strings with heap allocation -- Structs with multiple fields -- Enums with discriminant -- Arrays with indexing - -**Run:** -```bash -suicmez tests/codegen/test_all_types.sui -gcc tests/codegen/test_all_types.c -o test_all_types -./test_all_types -``` - -## Memory Management Strategy - -The codegen implements the following allocation strategy: - -### Stack-Allocated (Copyable) -- `int`, `float`, `bool`, `char` - passed by value -- Structs (stored directly, not as pointers) -- Enums (stored directly with discriminant + union) - -### Heap-Allocated (with Debug Visibility) -- **Arrays**: `int*` pointers created with C99 compound literals - ```c - int* arr = (int[]){1, 2, 3, 4, 5}; - ``` -- **Strings**: `char*` pointers to string constants - ```c - char* msg = "hello"; - ``` - -## Debug Output Feature - -Every statement generates debug output showing: -1. The executed statement -2. The resulting value (if applicable) - -**Format:** -```c -int x = 10; -printf("| int x = 10 | \n %d\n", x); -``` - -**Output:** -``` -| int x = 10 | - 10 -``` - -### Format Specifiers - -The system automatically selects the correct format: -- `%d` - integers and booleans -- `%f` - floats -- `%s` - strings (char*) -- `%p` - pointers and arrays - -## Compilation - -All generated C code compiles with standard C99: -```bash -gcc -std=c99 .c -o -``` - -## Running Tests Manually - -```bash -# Generate C code from .sui file -suicmez tests/codegen/test_comprehensive.sui - -# Compile the generated C code -gcc tests/codegen/test_comprehensive.c -o /tmp/test_comprehensive - -# Run with debug output -/tmp/test_comprehensive -``` - -## Expected Behavior - -All tests should: -1. āœ… Compile successfully with GCC -2. āœ… Generate valid C99 code -3. āœ… Execute without errors -4. āœ… Display debug output for each statement -5. āœ… Return correct exit codes - -## Implementation Notes - -- Structs are declared before enums in the output to avoid forward references -- Enum variant structs are generated before the union -- Array types use C99 compound literals for initialization -- All pointers are properly typed (not generic `void*`) -- Debug output uses `printf` with appropriate format specifiers diff --git a/tests/codegen/SUMMARY.md b/tests/codegen/SUMMARY.md deleted file mode 100644 index 95e0bb4..0000000 --- a/tests/codegen/SUMMARY.md +++ /dev/null @@ -1,175 +0,0 @@ -# Codegen Tests - Summary - -## Organization - -The codegen tests have been organized into a dedicated `tests/codegen/` subdirectory with the following structure: - -``` -tests/codegen/ -ā”œā”€ā”€ README.md # Comprehensive documentation -ā”œā”€ā”€ TESTING.md # Testing instructions -ā”œā”€ā”€ SUMMARY.md # This file -ā”œā”€ā”€ test_executable.* # Simple arithmetic test -ā”œā”€ā”€ test_array_simple.* # Array operations test -ā”œā”€ā”€ test_enum_simple.* # Enum types test -ā”œā”€ā”€ test_comprehensive.* # Mixed types test -└── test_all_types.* # Type coverage test -``` - -Each test has two files: -- `.sui` - Source code in the suicmez language -- `.c` - Generated C code with debug output - -## What Was Cleaned Up - -Removed from root directory: -- `simple.sui`, `simple_test.*` - Incomplete test files -- `syntax_test.sui` - Old syntax exploration -- `test_affine.sui`, `test_binding.sui` - Abandoned tests -- `test_linear*.sui` - Linear type system experiments -- `test_scoping.sui`, `test_shadow.sui` - Scoping tests -- Other misc test files - -Kept in root (valid existing tests): -- None - all valid tests are now organized in `tests/` subdirectories - -## Test Files - -### New Codegen Tests (in `tests/codegen/`) - -1. **test_executable** - Minimal executable test - - Basic integer operations - - Function calls - - Return values - -2. **test_array_simple** - Array functionality - - Array literals: `[1, 2, 3]` - - Array indexing: `arr[0]` - - Pointer-based array representation - -3. **test_enum_simple** - Enumeration types - - Enum variants - - Discriminant + union pattern - - Struct ordering - -4. **test_comprehensive** - Combined features - - All basic types (int, float, bool, string) - - Structs with multiple fields - - Enums with variants - - Arrays with complex operations - - Function calls with parameters - -5. **test_all_types** - Complete type coverage - - Exhaustive test of all language types - - Demonstrates each type independently - - Shows debug output for each - -### Existing Tests (preserved in `tests/`) - -- `arrays.sui` - Additional array tests -- `basic_types.sui/c` - Basic type tests -- `control_flow.sui/c` - If/while/for loops -- `enums.sui` - Enum functionality -- `functions.sui/c` - Function definitions -- `generics_comprehensive.sui/c` - Generic types -- `import_tests/` - Module imports -- `pointers.sui` - Pointer operations -- `structs.sui/c` - Struct definitions -- `traits.sui/c` - Trait system -- And more... - -## Features Demonstrated - -### Memory Management -- Stack allocation: `int`, `float`, `bool` -- Heap allocation: arrays with pointers -- Strings as `char*` -- Structs and enums stack-allocated - -### Language Features -- Variable declarations and assignments -- Function definitions and calls -- Struct literals with initialization -- Enum variants with discriminants -- Array literals and indexing -- Type conversions (implicit) - -### Debug Output -Every statement generates debug output: -```c -int x = 10; -printf("| int x = 10 | \n %d\n", x); -// Output: | int x = 10 | -// 10 -``` - -## Running the Tests - -### Quick Check -```bash -cd /home/nafi/langjam/suicmez -for f in tests/codegen/*.sui; do - ./target/debug/suicmez "$f" > /dev/null && echo "āœ“ $(basename $f)" -done -``` - -### Full Test Run -```bash -# Regenerate all C code -for f in tests/codegen/*.sui; do - ./target/debug/suicmez "$f" -done - -# Compile all tests -for f in tests/codegen/*.c; do - gcc "$f" -o "/tmp/$(basename ${f%.c})" -done - -# Run all tests -for exe in /tmp/test_*; do - echo "Running $(basename $exe)..." - "$exe" 2>&1 | head -5 - echo "" -done -``` - -### Individual Test -```bash -./target/debug/suicmez tests/codegen/test_comprehensive.sui -gcc tests/codegen/test_comprehensive.c -o /tmp/test -/tmp/test -``` - -## Quality Assurance - -All codegen tests: -- āœ… Generate valid C99 code -- āœ… Compile with GCC without errors -- āœ… Execute successfully -- āœ… Display proper debug output -- āœ… Return correct values -- āœ… Include comprehensive documentation - -## Documentation - -- **README.md** - Feature overview and structure -- **TESTING.md** - How to run and troubleshoot tests -- **SUMMARY.md** - This file, organization summary - -## Next Steps - -To add new codegen tests: -1. Create `test_feature.sui` in `tests/codegen/` -2. Run transpiler: `./target/debug/suicmez tests/codegen/test_feature.sui` -3. Verify C code: `gcc tests/codegen/test_feature.c -c` -4. Test execution: `gcc tests/codegen/test_feature.c -o /tmp/test && /tmp/test` -5. Document in README.md - -## Files Status - -āœ… All files properly organized -āœ… All tests generate valid C code -āœ… All tests compile and run -āœ… Documentation complete -āœ… Debug output working -āœ… Root directory cleaned diff --git a/tests/codegen/TESTING.md b/tests/codegen/TESTING.md deleted file mode 100644 index 621b862..0000000 --- a/tests/codegen/TESTING.md +++ /dev/null @@ -1,115 +0,0 @@ -# Running the Codegen Tests - -## Quick Start - -```bash -# Regenerate C code from all tests -for f in tests/codegen/*.sui; do - ./target/debug/suicmez "$f" -done - -# Compile and run a single test -gcc tests/codegen/test_comprehensive.c -o /tmp/test_comprehensive -/tmp/test_comprehensive -``` - -## Test Summary - -| Test | Purpose | Input | Output | -|------|---------|-------|--------| -| `test_executable.sui` | Simple arithmetic | Basic int operations | Exit code with result | -| `test_array_simple.sui` | Array operations | Array literal and indexing | Debug output with array values | -| `test_enum_simple.sui` | Enum types | Enum variant creation | Discriminant value | -| `test_comprehensive.sui` | Mixed types | All basic + complex types | Full debug trace | -| `test_all_types.sui` | Type coverage | Every language type | Debug output for each | - -## Running Individual Tests - -### 1. Array Test -```bash -./target/debug/suicmez tests/codegen/test_array_simple.sui -gcc tests/codegen/test_array_simple.c -o /tmp/array_test -/tmp/array_test -``` - -**Expected Output:** -``` -| int* arr = (int[]){1, 2, 3} | - 0x... -| int x = arr[0] | - 1 -``` - -### 2. Enum Test -```bash -./target/debug/suicmez tests/codegen/test_enum_simple.sui -gcc tests/codegen/test_enum_simple.c -o /tmp/enum_test -/tmp/enum_test -``` - -**Expected Output:** -``` -| struct Color c = (struct Color){ .discriminant = 0, .data = { .red = (struct Color_Red){} } } | - 0 -``` - -### 3. Comprehensive Test -```bash -./target/debug/suicmez tests/codegen/test_comprehensive.sui -gcc tests/codegen/test_comprehensive.c -o /tmp/comprehensive_test -/tmp/comprehensive_test -``` - -**Expected Output:** (full debug trace of all operations) -``` -| int x = 10 | - 10 -| int y = 20 | - 20 -| int sum = add(x, y) | - 30 -... (more output) -``` - -## Debugging the Codegen - -Each test's generated C file includes debug `printf` statements. To see what's happening: - -1. **Look at the generated C code:** - ```bash - cat tests/codegen/test_comprehensive.c - ``` - -2. **Run with debug output:** - ```bash - gcc tests/codegen/test_comprehensive.c -o /tmp/test - /tmp/test 2>&1 | head -20 - ``` - -3. **Check for compilation errors:** - ```bash - gcc tests/codegen/test_comprehensive.c -c -o /tmp/test.o - ``` - -## Verifying Correctness - -All tests should: -- āœ… Generate valid C99 code -- āœ… Compile without warnings -- āœ… Execute without segmentation faults -- āœ… Show proper debug output for each statement - -## Common Issues - -### Test fails to compile -- Check that the `.sui` file was properly transpiled -- Regenerate with: `./target/debug/suicmez tests/codegen/test_name.sui` - -### Debug output missing -- Ensure the printf statements are in the generated C code -- Check for return statements that might skip debug output - -### Wrong values printed -- The debug output uses automatic format specifiers (`%d`, `%f`, `%s`, `%p`) -- Struct types print the first field value -- Arrays print the pointer address diff --git a/tests/codegen/test_all_types.sui b/tests/codegen/test_all_types.sui deleted file mode 100644 index 5693164..0000000 --- a/tests/codegen/test_all_types.sui +++ /dev/null @@ -1,29 +0,0 @@ -struct Point - x: int, - y: int, -end - -enum Result - Ok, - Error, -end - -fn main() -> int do - # Test basic types - let int_val = 42; - let float_val = 3.14; - let bool_val = true; - let str_val = "Hello, World!"; - - # Test struct - let point = Point { x: 10, y: 20 }; - - # Test enum - let result = Result::Ok(); - - # Test array - let numbers = [1, 2, 3, 4, 5]; - let first_num = numbers[0]; - - first_num -end diff --git a/tests/codegen/test_array_simple.sui b/tests/codegen/test_array_simple.sui deleted file mode 100644 index 09e58dc..0000000 --- a/tests/codegen/test_array_simple.sui +++ /dev/null @@ -1,5 +0,0 @@ -fn main() -> int do - let arr = [1, 2, 3]; - let x = arr[0]; - x -end diff --git a/tests/codegen/test_comprehensive.sui b/tests/codegen/test_comprehensive.sui deleted file mode 100644 index 59556df..0000000 --- a/tests/codegen/test_comprehensive.sui +++ /dev/null @@ -1,36 +0,0 @@ -struct Point - x: int, - y: int, -end - -enum Status - Ok, - Error, -end - -fn add(a: int, b: int) -> int do - a + b -end - -fn main() -> int do - # Test stack-allocated types (copyable) - let x = 10; - let y = 20; - let sum = add(x, y); - - # Test struct (stack-allocated for now, but declared as such in language) - let p = Point { x: 5, y: 15 }; - let point_sum = p.x + p.y; - - # Test enum (stack-allocated for now) - let status = Status::Ok(); - - # Test array (heap-allocated) - let arr = [1, 2, 3, 4, 5]; - let first = arr[0]; - - # Test string (heap-allocated) - let msg = "hello"; - sum + point_sum + first - -end diff --git a/tests/codegen/test_enum_simple.sui b/tests/codegen/test_enum_simple.sui deleted file mode 100644 index 1f5900e..0000000 --- a/tests/codegen/test_enum_simple.sui +++ /dev/null @@ -1,10 +0,0 @@ -enum Color - Red, - Green, - Blue, -end - -fn main() -> int do - let c = Color::Red(); - 0 -end diff --git a/tests/codegen/test_executable.sui b/tests/codegen/test_executable.sui deleted file mode 100644 index 8115015..0000000 --- a/tests/codegen/test_executable.sui +++ /dev/null @@ -1,5 +0,0 @@ -fn main() -> int do - let x = 10; - let y = 20; - x + y -end diff --git a/tests/control_flow.c b/tests/control_flow.c new file mode 100644 index 0000000..a6acdcf --- /dev/null +++ b/tests/control_flow.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +int main(void); + + +int main(void) { + if (true) { + 1; + } else { + 0; + } + int i = 0; + while ((i < 5)) { + i = (i + 1); + } + return i; +} + diff --git a/tests/functions.c b/tests/functions.c new file mode 100644 index 0000000..ee37205 --- /dev/null +++ b/tests/functions.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include +int add(int x, int y); +int main(void); + + +int add(int x, int y) { + return (x + y); +} + +int main(void) { + int sum = add(5, 3); + struct T id = identity(42); + return sum; +} + diff --git a/tests/game_3d_improved.sui b/tests/game_3d_improved.sui deleted file mode 100644 index 878d7eb..0000000 --- a/tests/game_3d_improved.sui +++ /dev/null @@ -1,96 +0,0 @@ -# 3D Physics Game with Raylib and ODE - Improved with Collision Detection -# A bouncing cube demo that actually collides with the ground - -fn main() -> int do - # Initialize raylib - init_window(800, 600, "3D Physics Game - Improved") - defer close_window() - set_target_fps(60) - - # Initialize ODE - ode_init() - defer ode_close() - - # Create physics world - let world = ode_world_create() - defer ode_world_destroy(world) - let null_space = 0 as *() - let space = ode_simple_space_create(null_space) # null parent - defer ode_space_destroy(space) - - # Set gravity - ode_world_set_gravity(world, 0.0, -9.81, 0.0) - - # Create contact joint group - let contactgroup = ode_joint_group_create(0) - defer ode_joint_group_destroy(contactgroup) - - # Create a cube body - let body = ode_body_create(world) - defer ode_body_destroy(body) - - # Set cube mass (density 1.0, size 1x1x1) - ode_body_set_box_mass(body, 1.0, 1.0, 1.0, 1.0) - - # Set initial position (5 units up) - ode_body_set_position(body, 0.0, 5.0, 0.0) - - # Create geometry for the cube - let geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) - defer ode_geom_destroy(geom) - - # Attach geometry to body - ode_geom_set_body(geom, body) - - # Create ground plane (y = 0) - let ground_geom = ode_create_plane_geom(space, 0.0, 1.0, 0.0, 0.0) - defer ode_geom_destroy(ground_geom) - - # Camera position variables - let mut camera_pos_x = 0.0 - let mut camera_pos_y = 2.0 - let mut camera_pos_z = 10.0 - - # Cube position variables - let mut cube_x = 0.0 - let mut cube_y = 0.0 - let mut cube_z = 0.0 - - # Main game loop - let mut frame_count = 0 - while window_should_close() == false do - # IMPORTANT: Collision detection must happen BEFORE world step - ode_space_collide(world, space, contactgroup) - - # Step physics simulation - ode_world_step(world, 1.0 / 60.0) - - # Empty contact group after step to avoid accumulation - ode_joint_group_empty(contactgroup) - - # Get cube position - ode_body_get_position(body, &cube_x, &cube_y, &cube_z) - - # Drawing - begin_drawing() - clear_background(135, 206, 235, 255) # Sky blue - - begin_mode3d(camera_pos_x, camera_pos_y, camera_pos_z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 45.0, 0) - - # Draw ground plane - draw_cube(0.0, -1.0, 0.0, 20.0, 0.1, 20.0, 34, 139, 34, 255) # Green ground - - # Draw the physics cube - draw_cube(cube_x, cube_y, cube_z, 1.0, 1.0, 1.0, 255, 0, 0, 255) # Red cube - - # Draw wireframe for better visibility - draw_cube_wires(cube_x, cube_y, cube_z, 1.0, 1.0, 1.0, 0, 0, 0, 255) - - end_mode3d() - end_drawing() - - frame_count = frame_count + 1 - end - - 0 -end diff --git a/tests/generics_comprehensive.c b/tests/generics_comprehensive.c new file mode 100644 index 0000000..7c8a977 --- /dev/null +++ b/tests/generics_comprehensive.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include + +struct Box_string { + struct T value; +}; + +struct Option_bool_union { + struct Option_bool_Some some; + struct Option_bool_None none; +}; + +struct Option_int_union { + struct Option_int_Some some; + struct Option_int_None none; +}; + +struct Option_int_None { +}; + +struct Option_int { + int discriminant; + struct Option_int_union data; +}; + +struct Option_int_Some { + struct T field_0; +}; + +struct Option_bool_None { +}; + +struct Option_bool { + int discriminant; + struct Option_bool_union data; +}; + +struct Option_bool_Some { + struct T field_0; +}; + +struct Box_int { + struct T value; +}; + +int test_containers(void); + + +int test_containers(void) { + struct Box box_int = (struct Box){ .value = 42 }; + struct Box box_string = (struct Box){ .value = "Fermented" }; + struct Option some_int = (Option){ .discriminant = 0, .data = { .some = (Option_Some{ .field_0 = 10 }) } }; + struct Option some_bool = (Option){ .discriminant = 0, .data = { .some = (Option_Some{ .field_0 = true }) } }; + struct T unwrapped = unwrap(some_int); + struct T unwraped_bool = unwrap(some_bool); + return (box_int.value + unwrapped); +} + diff --git a/tests/import_tests/good_import.c b/tests/import_tests/good_import.c new file mode 100644 index 0000000..556be3d --- /dev/null +++ b/tests/import_tests/good_import.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +struct Point { + int x; + int y; +}; +int helper_func(void); +int main(void); + + +int helper_func(void) { + return 42; +} + +int main(void) { + return helper_func(); +} + diff --git a/tests/ode_test.sui b/tests/ode_test.sui deleted file mode 100644 index 0668995..0000000 --- a/tests/ode_test.sui +++ /dev/null @@ -1,20 +0,0 @@ -# ODE Integration Test -fn main() -> int do - # Initialize ODE - ode_init() - - # Create a world - let world = ode_world_create() - - # Set gravity (0, -9.81, 0) - ode_world_set_gravity(world, 0.0, -9.81, 0.0) - - # Step the simulation - ode_world_step(world, 0.016) # 60 FPS timestep - - # Clean up - ode_world_destroy(world) - ode_close() - - 0 -end \ No newline at end of file diff --git a/tests/ode_voxel_example.sui b/tests/ode_voxel_example.sui deleted file mode 100644 index 2cb253d..0000000 --- a/tests/ode_voxel_example.sui +++ /dev/null @@ -1,43 +0,0 @@ -# ODE Voxel Physics Example -fn main() -> int do - # Initialize ODE - ode_init() - - # Create world and space - let world = ode_world_create() - let space = ode_simple_space_create(0 as *()) # null parent - - # Set gravity - ode_world_set_gravity(world, 0.0, -9.81, 0.0) - - # Create a box body - let body = ode_body_create(world) - - # Set box mass (density 1.0, size 1x1x1) - ode_body_set_box_mass(body, 1.0, 1.0, 1.0, 1.0) - - # Set initial position (5 units up) - ode_body_set_position(body, 0.0, 5.0, 0.0) - - # Create geometry for the box - let geom = ode_create_box_geom(space, 1.0, 1.0, 1.0) - - # Attach geometry to body - ode_geom_set_body(geom, body) - - # Simulate for a few steps - let mut i = 0 - while i < 10 do - ode_world_step(world, 0.016) # 60 FPS - i = i + 1 - end - - # Clean up - ode_geom_destroy(geom) - ode_body_destroy(body) - ode_space_destroy(space) - ode_world_destroy(world) - ode_close() - - 0 -end \ No newline at end of file diff --git a/tests/structs.c b/tests/structs.c new file mode 100644 index 0000000..e8915e2 --- /dev/null +++ b/tests/structs.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include +struct Point { + int x; + int y; +}; +int main(void); + + +int main(void) { + struct Point p = (struct Point){ .x = 5, .y = 10 }; + struct Person person = (struct Person){ .name = "Alice", .age = 30 }; + return (p.x + person.age); +} + diff --git a/tests/structs.sui b/tests/structs.sui index 27c3a5a..0638ea6 100644 --- a/tests/structs.sui +++ b/tests/structs.sui @@ -4,14 +4,13 @@ struct Point y: int, end -struct Person +struct Person name: string, - age: int, + age: T, end fn main() -> int do let p = Point { x: 5, y: 10 }; let person = Person { name: "Alice", age: 30 }; - let _ = p.x + person.age; - 0 + p.x + person.age end diff --git a/tests/traits.c b/tests/traits.c new file mode 100644 index 0000000..a4a89b8 --- /dev/null +++ b/tests/traits.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +struct Number { + int value; +}; +char* Number_show(struct Number self); +int main(void); + + +char* Number_show(struct Number self) { + return "number"; +} + +int main(void) { + struct Number number = (struct Number){ .value = 40 }; + Number_show(number); + return 0; +} + diff --git a/tests/traits.sui b/tests/traits.sui old mode 100755 new mode 100644 index 51529b1..e1c8c79 Binary files a/tests/traits.sui and b/tests/traits.sui differ