Compare commits
3 Commits
1b1a5934f5
...
3f81104c99
Author | SHA1 | Date | |
---|---|---|---|
3f81104c99 | |||
b643c13582 | |||
e412a2e1d7 |
466
examples/cpu_raytracer.reid
Normal file
466
examples/cpu_raytracer.reid
Normal file
@ -0,0 +1,466 @@
|
||||
// First half of Ray Tracing in One Weekend, rendered to a SDL3 window rather
|
||||
// than an image file. Needs to be linked against SDL3, i.e.
|
||||
// `./cli cpu_raytracer.reid SDL3`
|
||||
|
||||
import std::print;
|
||||
import std::String;
|
||||
|
||||
///////////////////
|
||||
/// SDL externs ///
|
||||
///////////////////
|
||||
|
||||
// Helper struct for stack allocated const sized strings, because structs are
|
||||
// easier to create uninit than arrays.
|
||||
struct SDL_Window {}
|
||||
struct SDL_Renderer {}
|
||||
struct SDL_Texture {}
|
||||
struct SDL_Event { type: u32, reserved: [u8; 124] }
|
||||
struct SDL_FRect { x: f32, y: f32, w: f32, h: f32 }
|
||||
struct SDL_Rect { x: i32, y: i32, w: i32, h: i32 }
|
||||
extern fn SDL_malloc(size: u64) -> *u8;
|
||||
extern fn SDL_Init(flags: u32) -> bool;
|
||||
extern fn SDL_Quit();
|
||||
extern fn SDL_CreateWindowAndRenderer(title: *char, width: i32, height: i32, flags: i32,
|
||||
window_out: &mut *SDL_Window, renderer_out: &mut *SDL_Renderer) -> bool;
|
||||
extern fn SDL_Delay(ms: u32);
|
||||
extern fn SDL_SetRenderDrawColor(renderer: *SDL_Renderer, r: u8, g: u8, b: u8, a: u8);
|
||||
extern fn SDL_RenderClear(renderer: *SDL_Renderer);
|
||||
extern fn SDL_RenderPresent(renderer: *SDL_Renderer);
|
||||
extern fn SDL_HasEvent(event_type: u32) -> bool;
|
||||
extern fn SDL_PollEvent(event: &mut SDL_Event) -> bool;
|
||||
extern fn SDL_PumpEvents();
|
||||
extern fn SDL_FlushEvents(min_type: u32, max_type: u32);
|
||||
extern fn SDL_GetTicks() -> u64;
|
||||
extern fn SDL_SetWindowTitle(window: *SDL_Window, title: *char) -> bool;
|
||||
extern fn SDL_CreateTexture(renderer: *SDL_Renderer,
|
||||
pixel_format: u32, texture_access: u32, width: u32, height: u32) -> *SDL_Texture;
|
||||
extern fn SDL_RenderTexture(renderer: *SDL_Renderer,
|
||||
texture: *SDL_Texture, srcfrect: &SDL_FRect, dstfrect: &SDL_FRect) -> bool;
|
||||
extern fn SDL_UpdateTexture(texture: *SDL_Texture, rect: &SDL_Rect, pixels: *u8, pitch: u32) -> bool;
|
||||
extern fn SDL_GetError() -> *char;
|
||||
extern fn SDL_GetWindowSize(window: *SDL_Window, w: &mut i32, h: &mut i32) -> bool;
|
||||
extern fn SDL_rand(max_exclusive: u32) -> u32;
|
||||
extern fn SDL_SetTextureScaleMode(texture: *SDL_Texture, scale_mode: i32) -> bool;
|
||||
extern fn SDL_sqrtf(value: f32) -> f32;
|
||||
extern fn SDL_randf() -> f32;
|
||||
extern fn SDL_powf(value: f32, power: f32) -> f32;
|
||||
|
||||
// SDL error reporting helper
|
||||
fn print_sdl_error(context: *char) {
|
||||
let mut message = String::new();
|
||||
message = message + context + ": " + SDL_GetError();
|
||||
print(message);
|
||||
message.free();
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
/// Main setup and frame loop ///
|
||||
/////////////////////////////////
|
||||
|
||||
struct GameState {
|
||||
renderer: *SDL_Renderer,
|
||||
window: *SDL_Window,
|
||||
render_texture: *SDL_Texture,
|
||||
frame_counter: u32,
|
||||
last_fps_reset: u64,
|
||||
pixels: *u8,
|
||||
pixels_w: u32,
|
||||
pixels_h: u32,
|
||||
pixels_bpp: u32,
|
||||
}
|
||||
|
||||
fn main() -> i32 {
|
||||
let SDL_INIT_VIDEO = 32;
|
||||
let SDL_WINDOW_RESIZABLE = 32;
|
||||
let SDL_PIXELFORMAT_RGBA8888 = 373694468;
|
||||
let SDL_PIXELFORMAT_ABGR8888 = 376840196;
|
||||
let SDL_PIXELFORMAT_RGB24 = 386930691;
|
||||
let SDL_PIXELFORMAT_BGR24 = 390076419;
|
||||
let SDL_PIXELFORMAT_RGB96_FLOAT = 454057996;
|
||||
let SDL_PIXELFORMAT_BGR96_FLOAT = 457203724;
|
||||
let SDL_TEXTUREACCESS_STREAMING = 1;
|
||||
let SDL_SCALEMODE_NEAREST = 0;
|
||||
let SDL_SCALEMODE_LINEAR = 1;
|
||||
let SDL_SCALEMODE_PIXELART = 2;
|
||||
|
||||
let init_success = SDL_Init(SDL_INIT_VIDEO);
|
||||
if init_success == false {
|
||||
print_sdl_error("SDL init failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
let mut window = SDL_Window::null();
|
||||
let mut renderer = SDL_Renderer::null();
|
||||
let gfx_init_success = SDL_CreateWindowAndRenderer(
|
||||
"cpu raytracer", 640, 480, SDL_WINDOW_RESIZABLE,
|
||||
&mut window, &mut renderer
|
||||
);
|
||||
if gfx_init_success == false {
|
||||
print_sdl_error("SDL renderer and window creation failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
let width = 128;
|
||||
let height = 64;
|
||||
let bpp = 4;
|
||||
let render_texture = SDL_CreateTexture(renderer,
|
||||
SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||
SDL_SetTextureScaleMode(render_texture, SDL_SCALEMODE_NEAREST);
|
||||
|
||||
let pixels_len = (width * height * bpp) as u64;
|
||||
let pixels = SDL_malloc(pixels_len);
|
||||
let mut game_state = GameState {
|
||||
renderer: renderer,
|
||||
window: window,
|
||||
render_texture: render_texture,
|
||||
frame_counter: 0,
|
||||
last_fps_reset: 0,
|
||||
pixels: pixels,
|
||||
pixels_w: width,
|
||||
pixels_h: height,
|
||||
pixels_bpp: bpp,
|
||||
};
|
||||
|
||||
while frame_loop(&mut game_state) {}
|
||||
|
||||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn frame_loop(game_state: &mut GameState) -> bool {
|
||||
let mut event = SDL_Event { type: 0, reserved: [0; 124] };
|
||||
while (SDL_PollEvent(&mut event)) {
|
||||
if event.type == 256 { // SDL_EVENT_QUIT
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let mut screen_width = 0;
|
||||
let mut screen_height = 0;
|
||||
SDL_GetWindowSize(*game_state.window, &mut screen_width, &mut screen_height);
|
||||
|
||||
let renderer = *game_state.renderer;
|
||||
SDL_SetRenderDrawColor(renderer, 0, 50, 90, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
let w = *game_state.pixels_w;
|
||||
let h = *game_state.pixels_h;
|
||||
let bpp = *game_state.pixels_bpp;
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
render_pixel(x, y, game_state);
|
||||
}
|
||||
}
|
||||
|
||||
let texture_area = SDL_Rect { x: 0, y: 0, w: w as i32, h: h as i32 };
|
||||
if SDL_UpdateTexture(*game_state.render_texture, &texture_area, *game_state.pixels as *u8, bpp * w) == false {
|
||||
print_sdl_error("UpdateTexture error");
|
||||
}
|
||||
let src = SDL_FRect { x: 0.0, y: 0.0, w: w as f32, h: h as f32 };
|
||||
let aspect_ratio = src.w / src.h;
|
||||
let scaled_width = screen_height as f32 * aspect_ratio;
|
||||
let dst = SDL_FRect { x: (screen_width as f32 - scaled_width) / 2.0, y: 0.0, w: scaled_width, h: screen_height as f32 };
|
||||
if SDL_RenderTexture(renderer, *game_state.render_texture, &src, &dst) == false {
|
||||
print_sdl_error("RenderTexture error");
|
||||
}
|
||||
|
||||
SDL_RenderPresent(renderer);
|
||||
SDL_Delay(1);
|
||||
|
||||
*game_state.frame_counter = *game_state.frame_counter + 1;
|
||||
let t = SDL_GetTicks();
|
||||
if (t - *game_state.last_fps_reset) >= 1000 {
|
||||
let mut title = String::new();
|
||||
title = title + "cpu raytracer (" + *game_state.frame_counter as u64 + " fps)";
|
||||
SDL_SetWindowTitle(*game_state.window, title.inner);
|
||||
title.free();
|
||||
*game_state.frame_counter = 0;
|
||||
*game_state.last_fps_reset = t;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fn render_pixel(x: u32, y: u32, game_state: &mut GameState) {
|
||||
let w = *game_state.pixels_w;
|
||||
let h = *game_state.pixels_h;
|
||||
let bpp = *game_state.pixels_bpp;
|
||||
|
||||
let samples = 8;
|
||||
let old_sample_weight = 0.9;
|
||||
let new_sample_weight = 0.1 / samples as f32;
|
||||
let mut rgb = vec_mul_scalar(old_sample_weight, [
|
||||
srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 0]),
|
||||
srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 1]),
|
||||
srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 2])
|
||||
]);
|
||||
for sample in 0..samples {
|
||||
rgb = vec_add(rgb, vec_mul_scalar(new_sample_weight, shade(x, y, *game_state.frame_counter, w, h)));
|
||||
}
|
||||
*game_state.pixels[(x + y * w) * bpp + 0] = linear_to_srgb(rgb[0]);
|
||||
*game_state.pixels[(x + y * w) * bpp + 1] = linear_to_srgb(rgb[1]);
|
||||
*game_state.pixels[(x + y * w) * bpp + 2] = linear_to_srgb(rgb[2]);
|
||||
*game_state.pixels[(x + y * w) * bpp + 3] = 255;
|
||||
}
|
||||
|
||||
|
||||
/////////////////
|
||||
/// Rendering ///
|
||||
/////////////////
|
||||
|
||||
struct Ray {
|
||||
origin: [f32; 3],
|
||||
direction: [f32; 3],
|
||||
}
|
||||
|
||||
struct Material {
|
||||
// 0 = lambertian diffuse
|
||||
// 1 = mirror
|
||||
type: u32,
|
||||
// Generally the "color" of the surface (linear factors of how much of each
|
||||
// color channel this surface does not absorb), but the idea is that the
|
||||
// type governs what this means.
|
||||
linear_color: [f32; 3],
|
||||
}
|
||||
|
||||
struct Hit {
|
||||
hit: bool,
|
||||
front_face: bool,
|
||||
distance: f32,
|
||||
normal: [f32; 3],
|
||||
position: [f32; 3],
|
||||
material: Material,
|
||||
}
|
||||
impl Hit {
|
||||
fn none() -> Hit {
|
||||
Hit {
|
||||
hit: false, front_face: true, distance: 0.0, normal: [0.0; 3], position: [0.0; 3],
|
||||
material: Material { type: 0, linear_color: [0.0; 3] },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Sphere {
|
||||
center: [f32; 3],
|
||||
radius: f32,
|
||||
material: Material,
|
||||
}
|
||||
|
||||
fn shade(x: u32, y: u32, t: u32, w: u32, h: u32) -> [f32; 3] {
|
||||
let jitter_x = SDL_randf() - 0.5;
|
||||
let jitter_y = SDL_randf() - 0.5;
|
||||
|
||||
let pixel_scale = 1.0 / h as f32;
|
||||
let pixel_pos = [
|
||||
(x as f32 + jitter_x) * pixel_scale,
|
||||
1.0 - (y as f32 + jitter_y) * pixel_scale,
|
||||
-1.0
|
||||
];
|
||||
let camera_pos = [w as f32 * 0.5f32 * pixel_scale, h as f32 * 0.5f32 * pixel_scale, 0.0f32];
|
||||
let dir = vec_normalize(vec_sub(pixel_pos, camera_pos));
|
||||
let ray = Ray { origin: camera_pos, direction: dir };
|
||||
let beige_lambertian = Material { type: 0, linear_color: [0.3, 0.2, 0.1] };
|
||||
let green_lambertian = Material { type: 0, linear_color: [0.1, 0.5, 0.06] };
|
||||
let greenish_mirror = Material { type: 1, linear_color: [0.9, 1.0, 0.95] };
|
||||
let spheres = [
|
||||
// Ground
|
||||
Sphere { center: vec_sub(camera_pos, [0.0, 100001.0, 0.0]), radius: 100000.0, material: beige_lambertian },
|
||||
// Centered unit sphere
|
||||
Sphere { center: vec_add(camera_pos, [0.0, 0.0, 0.0 - 5.0]), radius: 1.0, material: green_lambertian },
|
||||
// The unit sphere on the right
|
||||
Sphere { center: vec_add(camera_pos, [2.0, 0.0, 0.0 - 6.0]), radius: 1.0, material: greenish_mirror }
|
||||
];
|
||||
return shade_world(ray, &spheres, 3);
|
||||
}
|
||||
|
||||
fn shade_world(ray: Ray, spheres: &[Sphere; 3], bounces_left: u8) -> [f32; 3] {
|
||||
if bounces_left == 0 {
|
||||
return [0.0, 0.0, 0.0];
|
||||
}
|
||||
|
||||
let mut closest_hit = Hit::none();
|
||||
closest_hit.distance = 100.0;
|
||||
for i in 0..3 {
|
||||
let sphere_hit = ray_sphere_closest_hit(ray, *spheres[i], [0.001, closest_hit.distance]);
|
||||
if sphere_hit.hit {
|
||||
closest_hit = sphere_hit;
|
||||
}
|
||||
}
|
||||
|
||||
if closest_hit.hit {
|
||||
//return vec_mul_scalar(0.5, vec_add(closest_hit.normal, [1.0, 1.0, 1.0])); // normal
|
||||
//return vec_mul_scalar(closest_hit.distance / 10.0, [1.0, 1.0, 1.0]); // depth
|
||||
if closest_hit.material.type == 0 {
|
||||
let bounce_dir = vec_normalize(vec_add(closest_hit.normal, random_unit_vec()));
|
||||
let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir };
|
||||
return vec_mul_componentwise(
|
||||
closest_hit.material.linear_color,
|
||||
shade_world(bounce_ray, spheres, bounces_left - 1)
|
||||
);
|
||||
} else if closest_hit.material.type == 1 {
|
||||
let bounce_dir = vec_reflect(ray.direction, closest_hit.normal);
|
||||
let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir };
|
||||
return vec_mul_componentwise(
|
||||
closest_hit.material.linear_color,
|
||||
shade_world(bounce_ray, spheres, bounces_left - 1)
|
||||
);
|
||||
} else {
|
||||
return [1.0, 0.0, 1.0];
|
||||
}
|
||||
}
|
||||
|
||||
return shade_sky(ray);
|
||||
}
|
||||
|
||||
fn shade_sky(ray: Ray) -> [f32; 3] {
|
||||
let a = 0.5 * (ray.direction[1] + 1.0);
|
||||
return vec_add(
|
||||
vec_mul_scalar(1.0 - a, [1.0, 1.0, 1.0]),
|
||||
vec_mul_scalar(a, [0.5, 0.7, 1.0])
|
||||
);
|
||||
}
|
||||
|
||||
// Returns the distance from the ray origin to the sphere, or -1.0 if the ray doesn't hit.
|
||||
fn ray_sphere_closest_hit(ray: Ray, sphere: Sphere, interval: [f32; 2]) -> Hit {
|
||||
let to_sphere = vec_sub(sphere.center, ray.origin);
|
||||
let h = vec_dot(ray.direction, to_sphere);
|
||||
let c = vec_length_squared(to_sphere) - sphere.radius * sphere.radius;
|
||||
let discriminant = h * h - c;
|
||||
if discriminant < 0.0 {
|
||||
return Hit::none();
|
||||
}
|
||||
|
||||
let discriminant_sqrt = SDL_sqrtf(discriminant);
|
||||
let mut distance = h - discriminant_sqrt;
|
||||
if interval_surrounds(interval, distance) == false {
|
||||
distance = h + discriminant_sqrt;
|
||||
if interval_surrounds(interval, distance) == false {
|
||||
return Hit::none();
|
||||
}
|
||||
}
|
||||
let hit_position = vec_add(ray.origin, vec_mul_scalar(distance, ray.direction));
|
||||
let mut front_face = true;
|
||||
let mut normal = vec_normalize(vec_sub(hit_position, sphere.center));
|
||||
if vec_dot(normal, ray.direction) > 0.0 {
|
||||
normal = vec_mul_scalar(-1.0, normal);
|
||||
front_face = false;
|
||||
}
|
||||
|
||||
return Hit {
|
||||
hit: true,
|
||||
front_face: front_face,
|
||||
distance: distance,
|
||||
normal: normal,
|
||||
position: hit_position,
|
||||
material: sphere.material,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//////////////////
|
||||
/// Other math ///
|
||||
//////////////////
|
||||
|
||||
fn clamp(min: f32, max: f32, value: f32) -> f32 {
|
||||
if value > max {
|
||||
return max;
|
||||
}
|
||||
if value < min {
|
||||
return min;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
fn abs(f: f32) -> f32 {
|
||||
if f < 0.0 {
|
||||
return f * -1.0;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
fn vec_add(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] {
|
||||
return [lhs[0] + rhs[0], lhs[1] + rhs[1], lhs[2] + rhs[2]];
|
||||
}
|
||||
|
||||
fn vec_sub(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] {
|
||||
return [lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2]];
|
||||
}
|
||||
|
||||
fn vec_dot(lhs: [f32; 3], rhs: [f32; 3]) -> f32 {
|
||||
return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2];
|
||||
}
|
||||
|
||||
fn vec_mul_componentwise(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] {
|
||||
return [lhs[0] * rhs[0], lhs[1] * rhs[1], lhs[2] * rhs[2]];
|
||||
}
|
||||
|
||||
fn vec_mul_scalar(lhs: f32, rhs: [f32; 3]) -> [f32; 3] {
|
||||
return [lhs * rhs[0], lhs * rhs[1], lhs * rhs[2]];
|
||||
}
|
||||
|
||||
fn vec_normalize(v: [f32; 3]) -> [f32; 3] {
|
||||
let len_reciprocal = 1.0f32 / SDL_sqrtf(vec_length_squared(v));
|
||||
return vec_mul_scalar(len_reciprocal, v);
|
||||
}
|
||||
|
||||
fn vec_length_squared(v: [f32; 3]) -> f32 {
|
||||
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
||||
}
|
||||
|
||||
fn vec_abs(v: [f32; 3]) -> [f32; 3] {
|
||||
return [abs(v[0]), abs(v[1]), abs(v[2])];
|
||||
}
|
||||
|
||||
fn vec_reflect(direction: [f32; 3], normal: [f32; 3]) -> [f32; 3] {
|
||||
return vec_sub(direction, vec_mul_scalar(2.0f32 * vec_dot(direction, normal), normal));
|
||||
}
|
||||
|
||||
fn interval_surrounds(interval: [f32; 2], value: f32) -> bool {
|
||||
return (interval[0] < value) && (value < interval[1]);
|
||||
}
|
||||
|
||||
fn random_unit_vec() -> [f32; 3] {
|
||||
let mut point = [
|
||||
SDL_randf() * 2.0f32 - 1.0f32,
|
||||
SDL_randf() * 2.0f32 - 1.0f32,
|
||||
SDL_randf() * 2.0f32 - 1.0f32
|
||||
];
|
||||
let mut lensq = vec_length_squared(point);
|
||||
while lensq > 1.0 {
|
||||
point = [
|
||||
SDL_randf() * 2.0f32 - 1.0f32,
|
||||
SDL_randf() * 2.0f32 - 1.0f32,
|
||||
SDL_randf() * 2.0f32 - 1.0f32
|
||||
];
|
||||
lensq = vec_length_squared(point);
|
||||
}
|
||||
let len_reciprocal = 1.0f32 / SDL_sqrtf(lensq);
|
||||
return vec_mul_scalar(len_reciprocal, point);
|
||||
}
|
||||
|
||||
fn random_unit_vec_on_hemi(normal: [f32; 3]) -> [f32; 3] {
|
||||
let rand_vec = random_unit_vec();
|
||||
if vec_dot(rand_vec, normal) < 0.0f32 {
|
||||
return vec_mul_scalar(0.0f32 - 1.0f32, rand_vec);
|
||||
}
|
||||
return rand_vec;
|
||||
}
|
||||
|
||||
fn linear_to_srgb(linear: f32) -> u8 {
|
||||
let mut floating_srgb = 0.0;
|
||||
if linear <= 0.0031308f32 {
|
||||
floating_srgb = 12.92f32 * linear;
|
||||
} else {
|
||||
floating_srgb = SDL_powf(linear as f32, 1.0 / 2.4) * 1.055f32 - 0.055f32;
|
||||
}
|
||||
let clamped = clamp(0.0, 1.0, floating_srgb);
|
||||
return (clamped * 255.999) as u8;
|
||||
}
|
||||
|
||||
fn srgb_to_linear(srgb: u8) -> f32 {
|
||||
let floating_srgb = srgb as f32 / 255.0;
|
||||
if floating_srgb <= 0.04045f32 {
|
||||
return floating_srgb / 12.92f32;
|
||||
}
|
||||
return SDL_powf((floating_srgb as f32 + 0.055) / 1.055, 2.4);
|
||||
}
|
@ -196,9 +196,9 @@ pub struct FunctionSignature {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SelfKind {
|
||||
Owned(TypeKind),
|
||||
Borrow(TypeKind),
|
||||
MutBorrow(TypeKind),
|
||||
Owned(Type),
|
||||
Borrow(Type),
|
||||
MutBorrow(Type),
|
||||
None,
|
||||
}
|
||||
|
||||
|
@ -696,9 +696,18 @@ impl Parse for SelfParam {
|
||||
};
|
||||
if name == "self" {
|
||||
match kind {
|
||||
SelfParamKind::BorrowMut => Ok(SelfParam(SelfKind::MutBorrow(TypeKind::Unknown))),
|
||||
SelfParamKind::Borrow => Ok(SelfParam(SelfKind::Borrow(TypeKind::Unknown))),
|
||||
SelfParamKind::Owned => Ok(SelfParam(SelfKind::Owned(TypeKind::Unknown))),
|
||||
SelfParamKind::BorrowMut => Ok(SelfParam(SelfKind::MutBorrow(Type(
|
||||
TypeKind::Unknown,
|
||||
stream.get_range_prev().unwrap(),
|
||||
)))),
|
||||
SelfParamKind::Borrow => Ok(SelfParam(SelfKind::Borrow(Type(
|
||||
TypeKind::Unknown,
|
||||
stream.get_range_prev().unwrap(),
|
||||
)))),
|
||||
SelfParamKind::Owned => Ok(SelfParam(SelfKind::Owned(Type(
|
||||
TypeKind::Unknown,
|
||||
stream.get_range_prev().unwrap(),
|
||||
)))),
|
||||
}
|
||||
} else {
|
||||
Err(stream.expected_err("self parameter")?)
|
||||
@ -1091,9 +1100,9 @@ impl Parse for AssociatedFunctionBlock {
|
||||
Some(Token::FnKeyword) | Some(Token::PubKeyword) => {
|
||||
let mut fun: FunctionDefinition = stream.parse()?;
|
||||
fun.0.self_kind = match fun.0.self_kind {
|
||||
SelfKind::Owned(_) => SelfKind::Owned(ty.0.clone()),
|
||||
SelfKind::Borrow(_) => SelfKind::Borrow(ty.0.clone()),
|
||||
SelfKind::MutBorrow(_) => SelfKind::MutBorrow(ty.0.clone()),
|
||||
SelfKind::Owned(_) => SelfKind::Owned(ty.clone()),
|
||||
SelfKind::Borrow(_) => SelfKind::Borrow(ty.clone()),
|
||||
SelfKind::MutBorrow(_) => SelfKind::MutBorrow(ty.clone()),
|
||||
SelfKind::None => SelfKind::None,
|
||||
};
|
||||
functions.push(fun);
|
||||
|
@ -3,8 +3,8 @@ use std::path::PathBuf;
|
||||
use crate::{
|
||||
ast::{self},
|
||||
mir::{
|
||||
self, CustomTypeKey, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind, StructField,
|
||||
StructType, WhileStatement,
|
||||
self, CustomTypeKey, FunctionParam, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind,
|
||||
StructField, StructType, WhileStatement,
|
||||
},
|
||||
};
|
||||
|
||||
@ -48,7 +48,11 @@ impl ast::Module {
|
||||
.params
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
|
||||
.map(|p| mir::FunctionParam {
|
||||
name: p.0,
|
||||
ty: p.1 .0.into_mir(module_id),
|
||||
meta: p.1 .1.as_meta(module_id),
|
||||
})
|
||||
.collect(),
|
||||
kind: mir::FunctionDefinitionKind::Extern(false),
|
||||
};
|
||||
@ -88,9 +92,17 @@ impl ast::Module {
|
||||
signature_range,
|
||||
}) => {
|
||||
binops.push(mir::BinopDefinition {
|
||||
lhs: (lhs.0.clone(), lhs.1 .0.into_mir(module_id)),
|
||||
lhs: mir::FunctionParam {
|
||||
name: lhs.0.clone(),
|
||||
ty: lhs.1 .0.into_mir(module_id),
|
||||
meta: lhs.1 .1.as_meta(module_id),
|
||||
},
|
||||
op: op.mir(),
|
||||
rhs: (rhs.0.clone(), rhs.1 .0.into_mir(module_id)),
|
||||
rhs: mir::FunctionParam {
|
||||
name: rhs.0.clone(),
|
||||
ty: rhs.1 .0.into_mir(module_id),
|
||||
meta: rhs.1 .1.as_meta(module_id),
|
||||
},
|
||||
return_type: return_ty.0.into_mir(module_id),
|
||||
fn_kind: mir::FunctionDefinitionKind::Local(
|
||||
block.into_mir(module_id),
|
||||
@ -129,25 +141,29 @@ impl ast::FunctionDefinition {
|
||||
|
||||
let mut params = Vec::new();
|
||||
match &signature.self_kind {
|
||||
ast::SelfKind::Borrow(type_kind) => params.push((
|
||||
"self".to_owned(),
|
||||
mir::TypeKind::Borrow(Box::new(type_kind.into_mir(module_id)), false),
|
||||
)),
|
||||
ast::SelfKind::MutBorrow(type_kind) => params.push((
|
||||
"self".to_owned(),
|
||||
mir::TypeKind::Borrow(Box::new(type_kind.into_mir(module_id)), true),
|
||||
)),
|
||||
ast::SelfKind::Owned(type_kind) => params.push(("self".to_owned(), type_kind.into_mir(module_id))),
|
||||
ast::SelfKind::Borrow(ty) => params.push(mir::FunctionParam {
|
||||
name: "self".to_owned(),
|
||||
ty: mir::TypeKind::Borrow(Box::new(ty.0.into_mir(module_id)), false),
|
||||
meta: ty.1.as_meta(module_id),
|
||||
}),
|
||||
ast::SelfKind::MutBorrow(ty) => params.push(mir::FunctionParam {
|
||||
name: "self".to_owned(),
|
||||
ty: mir::TypeKind::Borrow(Box::new(ty.0.into_mir(module_id)), true),
|
||||
meta: ty.1.as_meta(module_id),
|
||||
}),
|
||||
ast::SelfKind::Owned(ty) => params.push(mir::FunctionParam {
|
||||
name: "self".to_owned(),
|
||||
ty: ty.0.into_mir(module_id),
|
||||
meta: ty.1.as_meta(module_id),
|
||||
}),
|
||||
ast::SelfKind::None => {}
|
||||
}
|
||||
|
||||
params.extend(
|
||||
signature
|
||||
.params
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|p| (p.0, p.1 .0.into_mir(module_id))),
|
||||
);
|
||||
params.extend(signature.params.iter().cloned().map(|p| FunctionParam {
|
||||
name: p.0,
|
||||
ty: p.1 .0.into_mir(module_id),
|
||||
meta: p.1 .1.as_meta(module_id),
|
||||
}));
|
||||
mir::FunctionDefinition {
|
||||
name: signature.name.clone(),
|
||||
linkage_name: None,
|
||||
|
@ -7,7 +7,7 @@ use reid_lib::{
|
||||
|
||||
use mir::{CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, TypeKind, WhileStatement};
|
||||
|
||||
use crate::mir;
|
||||
use crate::mir::{self, FunctionParam, Metadata};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Allocator {
|
||||
@ -20,17 +20,13 @@ pub struct AllocatorScope<'ctx, 'a> {
|
||||
}
|
||||
|
||||
impl Allocator {
|
||||
pub fn from(
|
||||
func: &FunctionDefinitionKind,
|
||||
params: &Vec<(String, TypeKind)>,
|
||||
scope: &mut AllocatorScope,
|
||||
) -> Allocator {
|
||||
pub fn from(func: &FunctionDefinitionKind, params: &Vec<FunctionParam>, scope: &mut AllocatorScope) -> Allocator {
|
||||
func.allocate(scope, params)
|
||||
}
|
||||
|
||||
pub fn allocate(&mut self, name: &String, ty: &TypeKind) -> Option<InstructionValue> {
|
||||
pub fn allocate(&mut self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> {
|
||||
let mut allocs = self.allocations.iter().cloned().enumerate();
|
||||
let val = allocs.find(|a| a.1 .0 == *name && a.1 .1 == *ty);
|
||||
let val = allocs.find(|a| a.1 .0 == *meta && a.1 .1 == *ty);
|
||||
if let Some((i, _)) = val {
|
||||
self.allocations.remove(i);
|
||||
}
|
||||
@ -39,13 +35,13 @@ impl Allocator {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Allocation(String, TypeKind, InstructionValue);
|
||||
pub struct Allocation(Metadata, TypeKind, InstructionValue);
|
||||
|
||||
impl mir::FunctionDefinitionKind {
|
||||
fn allocate<'ctx, 'a>(
|
||||
&self,
|
||||
scope: &mut AllocatorScope<'ctx, 'a>,
|
||||
parameters: &Vec<(String, TypeKind)>,
|
||||
parameters: &Vec<mir::FunctionParam>,
|
||||
) -> Allocator {
|
||||
let mut allocated = Vec::new();
|
||||
match &self {
|
||||
@ -54,11 +50,11 @@ impl mir::FunctionDefinitionKind {
|
||||
let allocation = scope
|
||||
.block
|
||||
.build_named(
|
||||
param.0.clone(),
|
||||
reid_lib::Instr::Alloca(param.1.get_type(scope.type_values)),
|
||||
param.name.clone(),
|
||||
reid_lib::Instr::Alloca(param.ty.get_type(scope.type_values)),
|
||||
)
|
||||
.unwrap();
|
||||
allocated.push(Allocation(param.0.clone(), param.1.clone(), allocation));
|
||||
allocated.push(Allocation(param.meta, param.ty.clone(), allocation));
|
||||
}
|
||||
allocated.extend(block.allocate(scope));
|
||||
}
|
||||
@ -103,7 +99,7 @@ impl mir::Statement {
|
||||
)
|
||||
.unwrap();
|
||||
allocated.push(Allocation(
|
||||
named_variable_ref.1.clone(),
|
||||
named_variable_ref.2,
|
||||
named_variable_ref.0.clone(),
|
||||
allocation,
|
||||
));
|
||||
@ -154,11 +150,7 @@ impl mir::Expression {
|
||||
allocated.extend(lhs.allocate(scope));
|
||||
allocated.extend(rhs.allocate(scope));
|
||||
}
|
||||
mir::ExprKind::FunctionCall(FunctionCall { parameters, .. }) => {
|
||||
for param in parameters {
|
||||
allocated.extend(param.allocate(scope));
|
||||
}
|
||||
}
|
||||
mir::ExprKind::FunctionCall(fn_call) => allocated.extend(fn_call.allocate(&fn_call.name, scope)),
|
||||
mir::ExprKind::If(IfExpression(cond, then_ex, else_ex)) => {
|
||||
allocated.extend(cond.allocate(scope));
|
||||
allocated.extend(then_ex.allocate(scope));
|
||||
@ -174,13 +166,34 @@ impl mir::Expression {
|
||||
mir::ExprKind::CastTo(expression, _) => {
|
||||
allocated.extend(expression.allocate(scope));
|
||||
}
|
||||
mir::ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => {
|
||||
for param in parameters {
|
||||
allocated.extend(param.allocate(scope));
|
||||
}
|
||||
mir::ExprKind::AssociatedFunctionCall(ty, fn_call) => {
|
||||
allocated.extend(fn_call.allocate(&format!("{}::{}", ty, fn_call.name), scope))
|
||||
}
|
||||
}
|
||||
|
||||
allocated
|
||||
}
|
||||
}
|
||||
|
||||
impl mir::FunctionCall {
|
||||
fn allocate<'ctx, 'a>(&self, name: &String, scope: &mut AllocatorScope<'ctx, 'a>) -> Vec<Allocation> {
|
||||
let mut allocated = Vec::new();
|
||||
|
||||
for param in &self.parameters {
|
||||
allocated.extend(param.allocate(scope));
|
||||
}
|
||||
|
||||
if self.return_type != TypeKind::Void {
|
||||
let allocation = scope
|
||||
.block
|
||||
.build_named(
|
||||
name,
|
||||
reid_lib::Instr::Alloca(self.return_type.get_type(scope.type_values)),
|
||||
)
|
||||
.unwrap();
|
||||
allocated.push(Allocation(self.meta, self.return_type.clone(), allocation));
|
||||
}
|
||||
|
||||
allocated
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,10 @@ use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValue, Instr, Type}
|
||||
|
||||
use crate::{
|
||||
codegen::{ErrorKind, StackValueKind},
|
||||
mir::{BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, TypeKind},
|
||||
mir::{
|
||||
BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, FunctionParam,
|
||||
TypeKind,
|
||||
},
|
||||
};
|
||||
|
||||
use super::scope::{Scope, StackValue};
|
||||
@ -53,7 +56,11 @@ pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDef
|
||||
is_pub: true,
|
||||
is_imported: false,
|
||||
return_type: TypeKind::UserPtr(Box::new(ty.clone())),
|
||||
parameters: vec![(String::from("size"), TypeKind::U64)],
|
||||
parameters: vec![FunctionParam {
|
||||
name: String::from("size"),
|
||||
ty: TypeKind::U64,
|
||||
meta: Default::default(),
|
||||
}],
|
||||
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicAlloca(ty.clone()))),
|
||||
}),
|
||||
"null" => Some(FunctionDefinition {
|
||||
@ -74,9 +81,17 @@ where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||
{
|
||||
BinopDefinition {
|
||||
lhs: ("lhs".to_owned(), ty.clone()),
|
||||
lhs: FunctionParam {
|
||||
name: "lhs".to_owned(),
|
||||
ty: ty.clone(),
|
||||
meta: Default::default(),
|
||||
},
|
||||
op,
|
||||
rhs: ("rhs".to_owned(), ty.clone()),
|
||||
rhs: FunctionParam {
|
||||
name: "rhs".to_owned(),
|
||||
ty: ty.clone(),
|
||||
meta: Default::default(),
|
||||
},
|
||||
return_type: ty.clone(),
|
||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
|
||||
meta: Default::default(),
|
||||
@ -89,9 +104,17 @@ where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||
{
|
||||
BinopDefinition {
|
||||
lhs: ("lhs".to_owned(), lhs.clone()),
|
||||
lhs: FunctionParam {
|
||||
name: "lhs".to_owned(),
|
||||
ty: lhs.clone(),
|
||||
meta: Default::default(),
|
||||
},
|
||||
op,
|
||||
rhs: ("rhs".to_owned(), rhs.clone()),
|
||||
rhs: FunctionParam {
|
||||
name: "rhs".to_owned(),
|
||||
ty: rhs.clone(),
|
||||
meta: Default::default(),
|
||||
},
|
||||
return_type: lhs.clone(),
|
||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
|
||||
meta: Default::default(),
|
||||
@ -104,9 +127,17 @@ where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||
{
|
||||
BinopDefinition {
|
||||
lhs: ("lhs".to_owned(), ty.clone()),
|
||||
lhs: FunctionParam {
|
||||
name: "lhs".to_owned(),
|
||||
ty: ty.clone(),
|
||||
meta: Default::default(),
|
||||
},
|
||||
op,
|
||||
rhs: ("rhs".to_owned(), ty.clone()),
|
||||
rhs: FunctionParam {
|
||||
name: "rhs".to_owned(),
|
||||
ty: ty.clone(),
|
||||
meta: Default::default(),
|
||||
},
|
||||
return_type: TypeKind::Bool,
|
||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))),
|
||||
meta: Default::default(),
|
||||
|
@ -19,8 +19,8 @@ use crate::{
|
||||
self,
|
||||
implement::TypeCategory,
|
||||
pass::{AssociatedFunctionKey, BinopKey},
|
||||
CustomTypeKey, FunctionCall, FunctionDefinitionKind, NamedVariableRef, SourceModuleId, StructField, StructType,
|
||||
TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
|
||||
CustomTypeKey, FunctionCall, FunctionDefinitionKind, FunctionParam, NamedVariableRef, SourceModuleId,
|
||||
StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
|
||||
},
|
||||
util::try_all,
|
||||
};
|
||||
@ -182,7 +182,7 @@ impl mir::Module {
|
||||
let param_types: Vec<Type> = function
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|(_, p)| p.get_type(&type_values))
|
||||
.map(|FunctionParam { ty, .. }| ty.get_type(&type_values))
|
||||
.collect();
|
||||
|
||||
let is_main = self.is_main && function.name == "main";
|
||||
@ -222,7 +222,7 @@ impl mir::Module {
|
||||
let param_types: Vec<Type> = function
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|(_, p)| p.get_type(&type_values))
|
||||
.map(|FunctionParam { ty, .. }| ty.get_type(&type_values))
|
||||
.collect();
|
||||
|
||||
let is_main = self.is_main && function.name == "main";
|
||||
@ -263,11 +263,11 @@ impl mir::Module {
|
||||
for binop in &self.binop_defs {
|
||||
let binop_fn_name = format!(
|
||||
"binop.{}.{:?}.{}.{}",
|
||||
binop.lhs.1, binop.op, binop.rhs.1, binop.return_type
|
||||
binop.lhs.ty, binop.op, binop.rhs.ty, binop.return_type
|
||||
);
|
||||
binops.insert(
|
||||
BinopKey {
|
||||
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
||||
operator: binop.op,
|
||||
},
|
||||
StackBinopDefinition {
|
||||
@ -278,7 +278,7 @@ impl mir::Module {
|
||||
let ir_function = module.function(
|
||||
&binop_fn_name,
|
||||
binop.return_type.get_type(&type_values),
|
||||
vec![binop.lhs.1.get_type(&type_values), binop.rhs.1.get_type(&type_values)],
|
||||
vec![binop.lhs.ty.get_type(&type_values), binop.rhs.ty.get_type(&type_values)],
|
||||
FunctionFlags {
|
||||
is_pub: binop.exported,
|
||||
is_imported: binop.exported,
|
||||
@ -342,7 +342,7 @@ impl mir::Module {
|
||||
FunctionDefinitionKind::Extern(imported) => ScopeFunctionKind::UserGenerated(module.function(
|
||||
&binop_fn_name,
|
||||
binop.return_type.get_type(&type_values),
|
||||
vec![binop.lhs.1.get_type(&type_values), binop.rhs.1.get_type(&type_values)],
|
||||
vec![binop.lhs.ty.get_type(&type_values), binop.rhs.ty.get_type(&type_values)],
|
||||
FunctionFlags {
|
||||
is_extern: true,
|
||||
is_imported: *imported,
|
||||
@ -482,7 +482,7 @@ impl FunctionDefinitionKind {
|
||||
name: String,
|
||||
is_pub: bool,
|
||||
scope: &mut Scope,
|
||||
parameters: &Vec<(String, TypeKind)>,
|
||||
parameters: &Vec<FunctionParam>,
|
||||
return_type: &TypeKind,
|
||||
ir_function: &Function,
|
||||
debug_location: Option<DebugLocation>,
|
||||
@ -526,25 +526,25 @@ impl FunctionDefinitionKind {
|
||||
}
|
||||
|
||||
// Compile actual IR part
|
||||
for (i, (p_name, p_ty)) in parameters.iter().enumerate() {
|
||||
for (i, p) in parameters.iter().enumerate() {
|
||||
// Codegen actual parameters
|
||||
let arg_name = format!("arg.{}", p_name);
|
||||
let arg_name = format!("arg.{}", p.name);
|
||||
let param = scope
|
||||
.block
|
||||
.build_named(format!("{}.get", arg_name), Instr::Param(i))
|
||||
.unwrap();
|
||||
|
||||
let alloca = scope.allocate(&p_name, &p_ty).unwrap();
|
||||
let alloca = scope.allocate(&p.meta, &p.ty).unwrap();
|
||||
|
||||
scope
|
||||
.block
|
||||
.build_named(format!("{}.store", arg_name), Instr::Store(alloca, param))
|
||||
.unwrap();
|
||||
scope.stack_values.insert(
|
||||
p_name.clone(),
|
||||
p.name.clone(),
|
||||
StackValue(
|
||||
StackValueKind::mutable(p_ty.is_mutable(), alloca),
|
||||
TypeKind::CodegenPtr(Box::new(p_ty.clone())),
|
||||
StackValueKind::mutable(p.ty.is_mutable(), alloca),
|
||||
TypeKind::CodegenPtr(Box::new(p.ty.clone())),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -644,11 +644,11 @@ impl mir::Statement {
|
||||
});
|
||||
|
||||
match &self.0 {
|
||||
mir::StmtKind::Let(NamedVariableRef(ty, name, _), mutable, expression) => {
|
||||
mir::StmtKind::Let(NamedVariableRef(ty, name, meta), mutable, expression) => {
|
||||
let value = expression.codegen(scope, &state)?.unwrap();
|
||||
|
||||
let alloca = scope
|
||||
.allocate(name, &value.1)
|
||||
.allocate(meta, &value.1)
|
||||
.unwrap()
|
||||
.maybe_location(&mut scope.block, location.clone());
|
||||
|
||||
@ -1346,8 +1346,9 @@ fn codegen_function_call<'ctx, 'a>(
|
||||
|
||||
let ptr = if ret_type_kind != TypeKind::Void {
|
||||
let ptr = scope
|
||||
.block
|
||||
.build_named(&call.name, Instr::Alloca(ret_type.clone()))
|
||||
.allocator
|
||||
.borrow_mut()
|
||||
.allocate(&call.meta, &call.return_type)
|
||||
.unwrap();
|
||||
scope
|
||||
.block
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
lexer::FullToken,
|
||||
mir::{
|
||||
pass::{AssociatedFunctionKey, BinopKey},
|
||||
CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind,
|
||||
CustomTypeKey, FunctionParam, Metadata, SourceModuleId, TypeDefinition, TypeKind,
|
||||
},
|
||||
};
|
||||
|
||||
@ -67,8 +67,8 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
|
||||
self.type_values.get(key).and_then(|v| self.types.get(v))
|
||||
}
|
||||
|
||||
pub fn allocate(&self, name: &String, ty: &TypeKind) -> Option<InstructionValue> {
|
||||
self.allocator.borrow_mut().allocate(name, ty)
|
||||
pub fn allocate(&self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> {
|
||||
self.allocator.borrow_mut().allocate(meta, ty)
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +129,7 @@ impl StackValueKind {
|
||||
}
|
||||
|
||||
pub struct StackBinopDefinition<'ctx> {
|
||||
pub(super) parameters: ((String, TypeKind), (String, TypeKind)),
|
||||
pub(super) parameters: (FunctionParam, FunctionParam),
|
||||
pub(super) return_ty: TypeKind,
|
||||
pub(super) kind: ScopeFunctionKind<'ctx>,
|
||||
}
|
||||
@ -147,14 +147,14 @@ impl<'ctx> StackBinopDefinition<'ctx> {
|
||||
rhs: StackValue,
|
||||
scope: &mut Scope<'ctx, 'a>,
|
||||
) -> Result<StackValue, ErrorKind> {
|
||||
let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 {
|
||||
let (lhs, rhs) = if lhs.1 == self.parameters.0.ty && rhs.1 == self.parameters.1.ty {
|
||||
(lhs, rhs)
|
||||
} else {
|
||||
(rhs, lhs)
|
||||
};
|
||||
let name = format!(
|
||||
"binop.{}.{}.{}.call",
|
||||
self.parameters.0 .1, self.parameters.1 .1, self.return_ty
|
||||
self.parameters.0.ty, self.parameters.1.ty, self.return_ty
|
||||
);
|
||||
self.kind.codegen(&name, &[lhs, rhs], &self.return_ty, None, scope)
|
||||
}
|
||||
|
@ -131,11 +131,11 @@ pub fn perform_all_passes<'map>(
|
||||
binops
|
||||
.set(
|
||||
mir::pass::BinopKey {
|
||||
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||
params: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()),
|
||||
operator: intrinsic.op,
|
||||
},
|
||||
mir::pass::ScopeBinopDef {
|
||||
hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||
hands: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()),
|
||||
operator: intrinsic.op,
|
||||
return_ty: intrinsic.return_type.clone(),
|
||||
},
|
||||
|
@ -71,11 +71,11 @@ impl Display for BinopDefinition {
|
||||
f,
|
||||
"{}impl binop ({}: {:#}) {} ({}: {:#}) -> {:#} ",
|
||||
if self.exported { "exported " } else { "" },
|
||||
self.lhs.0,
|
||||
self.lhs.1,
|
||||
self.lhs.name,
|
||||
self.lhs.ty,
|
||||
self.op,
|
||||
self.rhs.0,
|
||||
self.rhs.1,
|
||||
self.rhs.name,
|
||||
self.rhs.ty,
|
||||
self.return_type
|
||||
)?;
|
||||
Display::fmt(&self.fn_kind, f)
|
||||
@ -132,7 +132,7 @@ impl Display for FunctionDefinition {
|
||||
self.name,
|
||||
self.parameters
|
||||
.iter()
|
||||
.map(|(n, t)| format!("{}: {:#}", n, t))
|
||||
.map(|FunctionParam { name, ty, .. }| format!("{}: {:#}", name, ty))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
self.return_type
|
||||
|
@ -11,8 +11,8 @@ use crate::{
|
||||
compile_module,
|
||||
error_raporting::{ErrorModules, ReidError},
|
||||
mir::{
|
||||
pass::BinopKey, BinopDefinition, CustomTypeKey, FunctionDefinitionKind, SourceModuleId, TypeDefinition,
|
||||
TypeKind,
|
||||
pass::BinopKey, BinopDefinition, CustomTypeKey, FunctionDefinitionKind, FunctionParam, SourceModuleId,
|
||||
TypeDefinition, TypeKind,
|
||||
},
|
||||
parse_module,
|
||||
};
|
||||
@ -220,10 +220,10 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
imported_types.extend(types);
|
||||
|
||||
let mut param_tys = Vec::new();
|
||||
for (param_name, param_ty) in &func.parameters {
|
||||
let types = import_type(¶m_ty, false);
|
||||
for param in &func.parameters {
|
||||
let types = import_type(¶m.ty, false);
|
||||
imported_types.extend(types);
|
||||
param_tys.push((param_name.clone(), param_ty.clone()));
|
||||
param_tys.push(param.clone());
|
||||
}
|
||||
|
||||
importer_module.functions.push(FunctionDefinition {
|
||||
@ -241,11 +241,11 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
imported_types.push((external_key, true));
|
||||
|
||||
for binop in &mut imported.binop_defs {
|
||||
if binop.lhs.1 != imported_ty && binop.rhs.1 != imported_ty {
|
||||
if binop.lhs.ty != imported_ty && binop.rhs.ty != imported_ty {
|
||||
continue;
|
||||
}
|
||||
let binop_key = BinopKey {
|
||||
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
||||
operator: binop.op,
|
||||
};
|
||||
if already_imported_binops.contains(&binop_key) {
|
||||
@ -309,10 +309,10 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
imported_types.extend(types);
|
||||
|
||||
let mut param_tys = Vec::new();
|
||||
for (param_name, param_ty) in &func.parameters {
|
||||
let types = import_type(¶m_ty, false);
|
||||
for param in &func.parameters {
|
||||
let types = import_type(¶m.ty, false);
|
||||
imported_types.extend(types);
|
||||
param_tys.push((param_name.clone(), param_ty.clone()));
|
||||
param_tys.push(param.clone());
|
||||
}
|
||||
|
||||
importer_module.associated_functions.push((
|
||||
@ -424,7 +424,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
if let Some(extern_types) = extern_types {
|
||||
function.return_type = function.return_type.update_imported(*extern_types, mod_id);
|
||||
for param in function.parameters.iter_mut() {
|
||||
param.1 = param.1.update_imported(extern_types, mod_id);
|
||||
param.ty = param.ty.update_imported(extern_types, mod_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -296,10 +296,17 @@ pub struct FunctionDefinition {
|
||||
/// Whether this module is from an external module, and has been imported
|
||||
pub is_imported: bool,
|
||||
pub return_type: TypeKind,
|
||||
pub parameters: Vec<(String, TypeKind)>,
|
||||
pub parameters: Vec<FunctionParam>,
|
||||
pub kind: FunctionDefinitionKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct FunctionParam {
|
||||
pub name: String,
|
||||
pub ty: TypeKind,
|
||||
pub meta: Metadata,
|
||||
}
|
||||
|
||||
pub enum SelfKind {
|
||||
Borrow,
|
||||
MutBorrow,
|
||||
@ -378,9 +385,9 @@ pub enum TypeDefinitionKind {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BinopDefinition {
|
||||
pub lhs: (String, TypeKind),
|
||||
pub lhs: FunctionParam,
|
||||
pub op: BinaryOperator,
|
||||
pub rhs: (String, TypeKind),
|
||||
pub rhs: FunctionParam,
|
||||
pub return_type: TypeKind,
|
||||
pub fn_kind: FunctionDefinitionKind,
|
||||
pub meta: Metadata,
|
||||
|
@ -187,7 +187,7 @@ impl<Data: Clone + Default> Scope<Data> {
|
||||
key.clone(),
|
||||
ScopeFunction {
|
||||
ret: func.return_type,
|
||||
params: func.parameters.iter().map(|(_, p)| p.clone()).collect(),
|
||||
params: func.parameters.iter().map(|p| p.ty.clone()).collect(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
@ -369,11 +369,11 @@ impl Context {
|
||||
.binops
|
||||
.set(
|
||||
BinopKey {
|
||||
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||
params: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()),
|
||||
operator: intrinsic.op,
|
||||
},
|
||||
ScopeBinopDef {
|
||||
hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||
hands: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()),
|
||||
operator: intrinsic.op,
|
||||
return_ty: intrinsic.return_type.clone(),
|
||||
},
|
||||
@ -407,11 +407,11 @@ impl Module {
|
||||
.binops
|
||||
.set(
|
||||
BinopKey {
|
||||
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
||||
operator: binop.op,
|
||||
},
|
||||
ScopeBinopDef {
|
||||
hands: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||
hands: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
||||
operator: binop.op,
|
||||
return_ty: binop.return_type.clone(),
|
||||
},
|
||||
@ -426,7 +426,7 @@ impl Module {
|
||||
function.name.clone(),
|
||||
ScopeFunction {
|
||||
ret: function.return_type.clone(),
|
||||
params: function.parameters.iter().cloned().map(|v| v.1).collect(),
|
||||
params: function.parameters.iter().cloned().map(|v| v.ty).collect(),
|
||||
},
|
||||
)
|
||||
.ok();
|
||||
@ -439,7 +439,7 @@ impl Module {
|
||||
AssociatedFunctionKey(ty.clone(), function.name.clone()),
|
||||
ScopeFunction {
|
||||
ret: function.return_type.clone(),
|
||||
params: function.parameters.iter().cloned().map(|v| v.1).collect(),
|
||||
params: function.parameters.iter().cloned().map(|v| v.ty).collect(),
|
||||
},
|
||||
)
|
||||
.ok();
|
||||
@ -466,9 +466,9 @@ impl FunctionDefinition {
|
||||
scope
|
||||
.variables
|
||||
.set(
|
||||
param.0.clone(),
|
||||
param.name.clone(),
|
||||
ScopeVariable {
|
||||
ty: param.1.clone(),
|
||||
ty: param.ty.clone(),
|
||||
mutable: false,
|
||||
},
|
||||
)
|
||||
|
@ -112,7 +112,7 @@ impl BinopDefinition {
|
||||
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> {
|
||||
for param in vec![&self.lhs, &self.rhs] {
|
||||
let param_t = state.or_else(
|
||||
param.1.assert_known(state),
|
||||
param.ty.assert_known(state),
|
||||
TypeKind::Vague(Vague::Unknown),
|
||||
self.signature(),
|
||||
);
|
||||
@ -120,13 +120,13 @@ impl BinopDefinition {
|
||||
.scope
|
||||
.variables
|
||||
.set(
|
||||
param.0.clone(),
|
||||
param.name.clone(),
|
||||
ScopeVariable {
|
||||
ty: param_t.clone(),
|
||||
mutable: param_t.is_mutable(),
|
||||
},
|
||||
)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.name.clone())));
|
||||
state.ok(res, self.signature());
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ impl FunctionDefinition {
|
||||
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> {
|
||||
for param in &self.parameters {
|
||||
let param_t = state.or_else(
|
||||
param.1.assert_known(state),
|
||||
param.ty.assert_known(state),
|
||||
TypeKind::Vague(Vague::Unknown),
|
||||
self.signature(),
|
||||
);
|
||||
@ -158,13 +158,13 @@ impl FunctionDefinition {
|
||||
.scope
|
||||
.variables
|
||||
.set(
|
||||
param.0.clone(),
|
||||
param.name.clone(),
|
||||
ScopeVariable {
|
||||
ty: param_t.clone(),
|
||||
mutable: param_t.is_mutable(),
|
||||
},
|
||||
)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.name.clone())));
|
||||
state.ok(res, self.signature());
|
||||
}
|
||||
|
||||
|
@ -87,16 +87,16 @@ impl<'t> Pass for TypeInference<'t> {
|
||||
let mut seen_binops = HashSet::new();
|
||||
for binop in &module.binop_defs {
|
||||
let binop_key = BinopKey {
|
||||
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
||||
operator: binop.op,
|
||||
};
|
||||
if seen_binops.contains(&binop_key) || (binop.lhs == binop.rhs && binop.lhs.1.category().is_simple_maths())
|
||||
if seen_binops.contains(&binop_key) || (binop.lhs == binop.rhs && binop.lhs.ty.category().is_simple_maths())
|
||||
{
|
||||
state.note_errors(
|
||||
&vec![ErrorKind::BinaryOpAlreadyDefined(
|
||||
binop.op,
|
||||
binop.lhs.1.clone(),
|
||||
binop.rhs.1.clone(),
|
||||
binop.lhs.ty.clone(),
|
||||
binop.rhs.ty.clone(),
|
||||
)],
|
||||
binop.signature(),
|
||||
);
|
||||
@ -107,7 +107,7 @@ impl<'t> Pass for TypeInference<'t> {
|
||||
.set(
|
||||
binop_key,
|
||||
crate::mir::pass::ScopeBinopDef {
|
||||
hands: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||
hands: (binop.lhs.ty.clone(), binop.rhs.ty.clone()),
|
||||
operator: binop.op,
|
||||
return_ty: binop.return_type.clone(),
|
||||
},
|
||||
@ -138,20 +138,20 @@ impl BinopDefinition {
|
||||
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> {
|
||||
let scope_hints = ScopeTypeRefs::from(type_refs);
|
||||
|
||||
let lhs_ty = state.or_else(self.lhs.1.assert_unvague(), Vague(Unknown), self.signature());
|
||||
let lhs_ty = state.or_else(self.lhs.ty.assert_unvague(), Vague(Unknown), self.signature());
|
||||
state.ok(
|
||||
scope_hints
|
||||
.new_var(self.lhs.0.clone(), false, &lhs_ty)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(self.lhs.0.clone()))),
|
||||
.new_var(self.lhs.name.clone(), false, &lhs_ty)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(self.lhs.name.clone()))),
|
||||
self.signature(),
|
||||
);
|
||||
|
||||
let rhs_ty = state.or_else(self.rhs.1.assert_unvague(), Vague(Unknown), self.signature());
|
||||
let rhs_ty = state.or_else(self.rhs.ty.assert_unvague(), Vague(Unknown), self.signature());
|
||||
|
||||
state.ok(
|
||||
scope_hints
|
||||
.new_var(self.rhs.0.clone(), false, &rhs_ty)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(self.rhs.0.clone()))),
|
||||
.new_var(self.rhs.name.clone(), false, &rhs_ty)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(self.rhs.name.clone()))),
|
||||
self.signature(),
|
||||
);
|
||||
|
||||
@ -170,10 +170,10 @@ impl FunctionDefinition {
|
||||
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> {
|
||||
let scope_refs = ScopeTypeRefs::from(type_refs);
|
||||
for param in &self.parameters {
|
||||
let param_t = state.or_else(param.1.assert_unvague(), Vague(Unknown), self.signature());
|
||||
let param_t = state.or_else(param.ty.assert_unvague(), Vague(Unknown), self.signature());
|
||||
let res = scope_refs
|
||||
.new_var(param.0.clone(), false, ¶m_t)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
|
||||
.new_var(param.name.clone(), false, ¶m_t)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.name.clone())));
|
||||
state.ok(res, self.signature());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user