Compare commits
10 Commits
2cb61de294
...
bf878c02a7
Author | SHA1 | Date | |
---|---|---|---|
bf878c02a7 | |||
4c9633132f | |||
45d381f865 | |||
17e8cf4807 | |||
c466b8eb2a | |||
8396aa4613 | |||
5149ef8727 | |||
307137d0d9 | |||
63f48f7df9 | |||
7ba3204803 |
@ -0,0 +1 @@
|
||||
max_width = 120
|
@ -53,7 +53,7 @@ Currently missing big features (TODOs) are:
|
||||
- Importable binops?
|
||||
|
||||
Big features that I want later but are not necessary:
|
||||
- Associated functions
|
||||
- Associated functions (for e.g. sizeof)
|
||||
- ~~User-defined binary operations~~ (DONE)
|
||||
- ~~Asymmetric binary operations (e.g. string + u32)~~ (DONE)
|
||||
- Error handling
|
||||
|
6
examples/a.reid
Normal file
6
examples/a.reid
Normal file
@ -0,0 +1,6 @@
|
||||
pub fn abs(f: f32) -> f32 {
|
||||
if f < 0.0 {
|
||||
return f * (0.0 - 1.0);
|
||||
}
|
||||
return f;
|
||||
}
|
@ -6,4 +6,4 @@ fn main() -> u32 {
|
||||
let other = 0o17;
|
||||
|
||||
return value * other + 7 * -value;
|
||||
}
|
||||
}
|
@ -11,7 +11,6 @@ fn main() -> u32 {
|
||||
second: 3,
|
||||
};
|
||||
|
||||
value.second = 17;
|
||||
|
||||
return value.second;
|
||||
}
|
||||
|
469
foo.reid
Normal file
469
foo.reid
Normal file
@ -0,0 +1,469 @@
|
||||
import std::concat_strings;
|
||||
import std::print;
|
||||
import std::from_str;
|
||||
import std::free_string;
|
||||
import std::add_num_to_str;
|
||||
|
||||
///////////////////
|
||||
/// 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 = from_str(context);
|
||||
|
||||
let delim = from_str(": ");
|
||||
concat_strings(&mut message, delim);
|
||||
free_string(&delim);
|
||||
|
||||
let error_msg = from_str(SDL_GetError());
|
||||
concat_strings(&mut message, error_msg);
|
||||
free_string(&error_msg);
|
||||
|
||||
print(message);
|
||||
|
||||
free_string(&message);
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
/// 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_malloc(1) as *SDL_Window;
|
||||
let mut renderer = SDL_malloc(1) as *SDL_Renderer;
|
||||
let gfx_init_success = SDL_CreateWindowAndRenderer(
|
||||
"graphical reid program", 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 = 320;
|
||||
let height = 240;
|
||||
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 {};
|
||||
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 = from_str("graphical reid program ");
|
||||
add_num_to_str(&mut title, *game_state.frame_counter as u64);
|
||||
let fps_unit = from_str(" fps");
|
||||
concat_strings(&mut title, fps_unit);
|
||||
free_string(&fps_unit);
|
||||
SDL_SetWindowTitle(*game_state.window, title.inner);
|
||||
free_string(&title);
|
||||
*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 = 1;
|
||||
let old_sample_weight = 0.75;
|
||||
let new_sample_weight = 0.25 / 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,
|
||||
}
|
||||
|
||||
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,
|
||||
0.0 - 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 ray_distance = 100.0;
|
||||
let mut closest_hit = Hit { hit: false, front_face: false, distance: ray_distance };
|
||||
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 { hit: false };
|
||||
}
|
||||
|
||||
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 { hit: false };
|
||||
}
|
||||
}
|
||||
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(0.0 - 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 * (0.0 - 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);
|
||||
}
|
@ -38,7 +38,7 @@ pub fn new_string() -> String {
|
||||
}
|
||||
|
||||
pub fn from_str(str: *char) -> String {
|
||||
let length = str_length(str);
|
||||
let length = str_length(str) as u64;
|
||||
let mut new = new_string();
|
||||
let static = String {
|
||||
inner: str,
|
||||
|
@ -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, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind, StructField,
|
||||
StructType, WhileStatement,
|
||||
},
|
||||
};
|
||||
|
||||
@ -162,9 +162,7 @@ impl ast::Block {
|
||||
*range,
|
||||
),
|
||||
ast::BlockLevelStatement::Import { _i } => todo!(),
|
||||
ast::BlockLevelStatement::Expression(e) => {
|
||||
(StmtKind::Expression(e.process(module_id)), e.1)
|
||||
}
|
||||
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process(module_id)), e.1),
|
||||
ast::BlockLevelStatement::Return(_, e) => {
|
||||
if let Some(e) = e {
|
||||
(StmtKind::Expression(e.process(module_id)), e.1)
|
||||
@ -197,11 +195,10 @@ impl ast::Block {
|
||||
counter_range.as_meta(module_id),
|
||||
)),
|
||||
Box::new(mir::Expression(
|
||||
mir::ExprKind::Literal(mir::Literal::Vague(
|
||||
mir::VagueLiteral::Number(1),
|
||||
)),
|
||||
mir::ExprKind::Literal(mir::Literal::Vague(mir::VagueLiteral::Number(1))),
|
||||
counter_range.as_meta(module_id),
|
||||
)),
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
),
|
||||
counter_range.as_meta(module_id),
|
||||
),
|
||||
@ -220,6 +217,7 @@ impl ast::Block {
|
||||
counter_range.as_meta(module_id),
|
||||
)),
|
||||
Box::new(end.process(module_id)),
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
),
|
||||
counter_range.as_meta(module_id),
|
||||
),
|
||||
@ -292,22 +290,15 @@ impl ast::Expression {
|
||||
binary_operator.mir(),
|
||||
Box::new(lhs.process(module_id)),
|
||||
Box::new(rhs.process(module_id)),
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
),
|
||||
ast::ExpressionKind::FunctionCall(fn_call_expr) => {
|
||||
mir::ExprKind::FunctionCall(mir::FunctionCall {
|
||||
name: fn_call_expr.0.clone(),
|
||||
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
parameters: fn_call_expr
|
||||
.1
|
||||
.iter()
|
||||
.map(|e| e.process(module_id))
|
||||
.collect(),
|
||||
meta: fn_call_expr.2.as_meta(module_id),
|
||||
})
|
||||
}
|
||||
ast::ExpressionKind::BlockExpr(block) => {
|
||||
mir::ExprKind::Block(block.into_mir(module_id))
|
||||
}
|
||||
ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall {
|
||||
name: fn_call_expr.0.clone(),
|
||||
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
parameters: fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(),
|
||||
meta: fn_call_expr.2.as_meta(module_id),
|
||||
}),
|
||||
ast::ExpressionKind::BlockExpr(block) => mir::ExprKind::Block(block.into_mir(module_id)),
|
||||
ast::ExpressionKind::IfExpr(if_expression) => {
|
||||
let cond = if_expression.0.process(module_id);
|
||||
let then_block = if_expression.1.process(module_id);
|
||||
@ -364,6 +355,7 @@ impl ast::Expression {
|
||||
expr.1.as_meta(module_id),
|
||||
)),
|
||||
Box::new(expr.process(module_id)),
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
),
|
||||
ast::UnaryOperator::Minus => mir::ExprKind::BinOp(
|
||||
mir::BinaryOperator::Minus,
|
||||
@ -372,6 +364,7 @@ impl ast::Expression {
|
||||
expr.1.as_meta(module_id),
|
||||
)),
|
||||
Box::new(expr.process(module_id)),
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
),
|
||||
},
|
||||
ast::ExpressionKind::CastTo(expression, ty) => mir::ExprKind::CastTo(
|
||||
@ -457,15 +450,11 @@ impl ast::TypeKind {
|
||||
ast::TypeKind::Array(type_kind, length) => {
|
||||
mir::TypeKind::Array(Box::new(type_kind.clone().into_mir(source_mod)), *length)
|
||||
}
|
||||
ast::TypeKind::Custom(name) => {
|
||||
mir::TypeKind::CustomType(CustomTypeKey(name.clone(), source_mod))
|
||||
}
|
||||
ast::TypeKind::Custom(name) => mir::TypeKind::CustomType(CustomTypeKey(name.clone(), source_mod)),
|
||||
ast::TypeKind::Borrow(type_kind, mutable) => {
|
||||
mir::TypeKind::Borrow(Box::new(type_kind.clone().into_mir(source_mod)), *mutable)
|
||||
}
|
||||
ast::TypeKind::Ptr(type_kind) => {
|
||||
mir::TypeKind::UserPtr(Box::new(type_kind.clone().into_mir(source_mod)))
|
||||
}
|
||||
ast::TypeKind::Ptr(type_kind) => mir::TypeKind::UserPtr(Box::new(type_kind.clone().into_mir(source_mod))),
|
||||
ast::TypeKind::F16 => mir::TypeKind::F16,
|
||||
ast::TypeKind::F32B => mir::TypeKind::F32B,
|
||||
ast::TypeKind::F32 => mir::TypeKind::F32,
|
||||
|
@ -6,8 +6,7 @@ use reid_lib::{
|
||||
};
|
||||
|
||||
use crate::mir::{
|
||||
self, CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, SourceModuleId,
|
||||
TypeKind, WhileStatement,
|
||||
self, CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, SourceModuleId, TypeKind, WhileStatement,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -74,9 +73,7 @@ impl mir::FunctionDefinitionKind {
|
||||
mir::FunctionDefinitionKind::Intrinsic(_) => {}
|
||||
}
|
||||
|
||||
Allocator {
|
||||
allocations: allocated,
|
||||
}
|
||||
Allocator { allocations: allocated }
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,9 +123,7 @@ impl mir::Statement {
|
||||
crate::mir::StmtKind::Expression(expression) => {
|
||||
allocated.extend(expression.allocate(scope));
|
||||
}
|
||||
crate::mir::StmtKind::While(WhileStatement {
|
||||
condition, block, ..
|
||||
}) => {
|
||||
crate::mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
|
||||
allocated.extend(condition.allocate(scope));
|
||||
allocated.extend(block.allocate(scope));
|
||||
}
|
||||
@ -162,7 +157,7 @@ impl mir::Expression {
|
||||
}
|
||||
}
|
||||
crate::mir::ExprKind::Literal(_) => {}
|
||||
crate::mir::ExprKind::BinOp(_, lhs, rhs) => {
|
||||
crate::mir::ExprKind::BinOp(_, lhs, rhs, _) => {
|
||||
allocated.extend(lhs.allocate(scope));
|
||||
allocated.extend(rhs.allocate(scope));
|
||||
}
|
||||
|
@ -1,78 +1,286 @@
|
||||
use reid_lib::{builder::InstructionValue, Instr};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use reid_lib::{builder::InstructionValue, CmpPredicate, Instr};
|
||||
|
||||
use crate::{
|
||||
codegen::{ErrorKind, StackValueKind},
|
||||
mir::{BinopDefinition, FunctionDefinition, TypeKind},
|
||||
mir::{BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, TypeKind},
|
||||
};
|
||||
|
||||
use super::scope::{Scope, StackValue};
|
||||
|
||||
const INTEGERS: [TypeKind; 10] = [
|
||||
TypeKind::U8,
|
||||
TypeKind::U16,
|
||||
TypeKind::U32,
|
||||
TypeKind::U64,
|
||||
TypeKind::U128,
|
||||
TypeKind::I8,
|
||||
TypeKind::I16,
|
||||
TypeKind::I32,
|
||||
TypeKind::I64,
|
||||
TypeKind::I128,
|
||||
];
|
||||
|
||||
const FLOATS: [TypeKind; 7] = [
|
||||
TypeKind::F16,
|
||||
TypeKind::F32,
|
||||
TypeKind::F32B,
|
||||
TypeKind::F64,
|
||||
TypeKind::F80,
|
||||
TypeKind::F128,
|
||||
TypeKind::F128PPC,
|
||||
];
|
||||
|
||||
pub fn form_intrinsics() -> Vec<FunctionDefinition> {
|
||||
let intrinsics = Vec::new();
|
||||
|
||||
intrinsics
|
||||
}
|
||||
|
||||
fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
|
||||
where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||
{
|
||||
BinopDefinition {
|
||||
lhs: ("lhs".to_owned(), ty.clone()),
|
||||
op,
|
||||
rhs: ("rhs".to_owned(), ty.clone()),
|
||||
return_type: ty.clone(),
|
||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
|
||||
meta: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn boolean_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
|
||||
where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||
{
|
||||
BinopDefinition {
|
||||
lhs: ("lhs".to_owned(), ty.clone()),
|
||||
op,
|
||||
rhs: ("rhs".to_owned(), ty.clone()),
|
||||
return_type: TypeKind::Bool,
|
||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))),
|
||||
meta: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
|
||||
let mut intrinsics = Vec::new();
|
||||
|
||||
use BinaryOperator::*;
|
||||
|
||||
for ty in INTEGERS {
|
||||
intrinsics.push(simple_binop_def(Add, &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::Add(lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(simple_binop_def(Mult, &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::Mul(lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(simple_binop_def(Minus, &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::Sub(lhs, rhs)).unwrap()
|
||||
}));
|
||||
if ty.signed() {
|
||||
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::SDiv(lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
|
||||
let div = scope.block.build(Instr::SDiv(lhs, rhs)).unwrap();
|
||||
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
|
||||
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
|
||||
}));
|
||||
} else {
|
||||
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::UDiv(lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
|
||||
let div = scope.block.build(Instr::UDiv(lhs, rhs)).unwrap();
|
||||
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
|
||||
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
|
||||
}));
|
||||
}
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::ICmp(CmpPredicate::GT, lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GE), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::ICmp(CmpPredicate::GE, lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LT), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::ICmp(CmpPredicate::LT, lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LE), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::ICmp(CmpPredicate::LE, lhs, rhs)).unwrap()
|
||||
}));
|
||||
}
|
||||
for ty in INTEGERS.iter().chain(&[TypeKind::Bool, TypeKind::Char]) {
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::ICmp(CmpPredicate::EQ, lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::ICmp(CmpPredicate::NE, lhs, rhs)).unwrap()
|
||||
}));
|
||||
}
|
||||
for ty in FLOATS {
|
||||
intrinsics.push(simple_binop_def(BinaryOperator::Add, &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FAdd(lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(simple_binop_def(BinaryOperator::Mult, &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FMul(lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(simple_binop_def(BinaryOperator::Minus, &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FSub(lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FDiv(lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
|
||||
let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap();
|
||||
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
|
||||
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FCmp(CmpPredicate::NE, lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FCmp(CmpPredicate::GT, lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GE), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FCmp(CmpPredicate::GE, lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LT), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FCmp(CmpPredicate::LT, lhs, rhs)).unwrap()
|
||||
}));
|
||||
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LE), &ty, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::FCmp(CmpPredicate::LE, lhs, rhs)).unwrap()
|
||||
}));
|
||||
}
|
||||
|
||||
intrinsics.push(boolean_binop_def(And, &TypeKind::Bool, |scope, lhs, rhs| {
|
||||
scope.block.build(Instr::And(lhs, rhs)).unwrap()
|
||||
}));
|
||||
|
||||
intrinsics
|
||||
}
|
||||
|
||||
pub trait IntrinsicFunction: std::fmt::Debug {
|
||||
fn codegen<'ctx, 'a>(
|
||||
&self,
|
||||
scope: &mut Scope<'ctx, 'a>,
|
||||
params: &[InstructionValue],
|
||||
) -> Result<StackValue, ErrorKind>;
|
||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[&StackValue]) -> Result<StackValue, ErrorKind>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IntrinsicIAdd(TypeKind);
|
||||
#[derive(Clone)]
|
||||
pub struct IntrinsicSimpleInstr<T>(T)
|
||||
where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
||||
|
||||
impl IntrinsicFunction for IntrinsicIAdd {
|
||||
fn codegen<'ctx, 'a>(
|
||||
&self,
|
||||
scope: &mut Scope<'ctx, 'a>,
|
||||
params: &[InstructionValue],
|
||||
) -> Result<StackValue, ErrorKind> {
|
||||
let lhs = params.get(0).unwrap();
|
||||
let rhs = params.get(1).unwrap();
|
||||
let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
|
||||
Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
||||
impl<T> std::fmt::Debug for IntrinsicSimpleInstr<T>
|
||||
where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("IntrinsicSimpleInstr").finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IntrinsicUDiv(TypeKind);
|
||||
|
||||
impl IntrinsicFunction for IntrinsicUDiv {
|
||||
fn codegen<'ctx, 'a>(
|
||||
&self,
|
||||
scope: &mut Scope<'ctx, 'a>,
|
||||
params: &[InstructionValue],
|
||||
) -> Result<StackValue, ErrorKind> {
|
||||
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T>
|
||||
where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||
{
|
||||
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[&StackValue]) -> Result<StackValue, ErrorKind> {
|
||||
let lhs = params.get(0).unwrap();
|
||||
let rhs = params.get(1).unwrap();
|
||||
let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
||||
Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
||||
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
|
||||
Ok(StackValue(StackValueKind::Literal(instr), lhs.1.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IntrinsicUMod(TypeKind);
|
||||
#[derive(Clone)]
|
||||
pub struct IntrinsicBooleanInstr<T>(T)
|
||||
where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
||||
|
||||
impl IntrinsicFunction for IntrinsicUMod {
|
||||
fn codegen<'ctx, 'a>(
|
||||
&self,
|
||||
scope: &mut Scope<'ctx, 'a>,
|
||||
params: &[InstructionValue],
|
||||
) -> Result<StackValue, ErrorKind> {
|
||||
let lhs = params.get(0).unwrap();
|
||||
let rhs = params.get(1).unwrap();
|
||||
let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
||||
let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap();
|
||||
let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap();
|
||||
Ok(StackValue(StackValueKind::Literal(sub), self.0.clone()))
|
||||
impl<T> std::fmt::Debug for IntrinsicBooleanInstr<T>
|
||||
where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("IntrinsicBooleanInstr").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> IntrinsicFunction for IntrinsicBooleanInstr<T>
|
||||
where
|
||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||
{
|
||||
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[&StackValue]) -> Result<StackValue, ErrorKind> {
|
||||
let lhs = params.get(0).unwrap();
|
||||
let rhs = params.get(1).unwrap();
|
||||
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
|
||||
Ok(StackValue(StackValueKind::Literal(instr), TypeKind::Bool))
|
||||
}
|
||||
}
|
||||
|
||||
// impl IntrinsicFunction for IntrinsicIAdd {
|
||||
// fn codegen<'ctx, 'a>(
|
||||
// &self,
|
||||
// scope: &mut Scope<'ctx, 'a>,
|
||||
// params: &[InstructionValue],
|
||||
// ) -> Result<StackValue, ErrorKind> {
|
||||
// let lhs = params.get(0).unwrap();
|
||||
// let rhs = params.get(1).unwrap();
|
||||
// let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
|
||||
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[derive(Debug, Clone)]
|
||||
// pub struct IntrinsicIAdd(TypeKind);
|
||||
|
||||
// impl IntrinsicFunction for IntrinsicIAdd {
|
||||
// fn codegen<'ctx, 'a>(
|
||||
// &self,
|
||||
// scope: &mut Scope<'ctx, 'a>,
|
||||
// params: &[InstructionValue],
|
||||
// ) -> Result<StackValue, ErrorKind> {
|
||||
// let lhs = params.get(0).unwrap();
|
||||
// let rhs = params.get(1).unwrap();
|
||||
// let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
|
||||
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[derive(Debug, Clone)]
|
||||
// pub struct IntrinsicUDiv(TypeKind);
|
||||
|
||||
// impl IntrinsicFunction for IntrinsicUDiv {
|
||||
// fn codegen<'ctx, 'a>(
|
||||
// &self,
|
||||
// scope: &mut Scope<'ctx, 'a>,
|
||||
// params: &[InstructionValue],
|
||||
// ) -> Result<StackValue, ErrorKind> {
|
||||
// let lhs = params.get(0).unwrap();
|
||||
// let rhs = params.get(1).unwrap();
|
||||
// let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
||||
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[derive(Debug, Clone)]
|
||||
// pub struct IntrinsicUMod(TypeKind);
|
||||
|
||||
// impl IntrinsicFunction for IntrinsicUMod {
|
||||
// fn codegen<'ctx, 'a>(
|
||||
// &self,
|
||||
// scope: &mut Scope<'ctx, 'a>,
|
||||
// params: &[InstructionValue],
|
||||
// ) -> Result<StackValue, ErrorKind> {
|
||||
// let lhs = params.get(0).unwrap();
|
||||
// let rhs = params.get(1).unwrap();
|
||||
// let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
|
||||
// let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap();
|
||||
// let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap();
|
||||
// Ok(StackValue(StackValueKind::Literal(sub), self.0.clone()))
|
||||
// }
|
||||
// }
|
||||
|
@ -5,20 +5,18 @@ use intrinsics::*;
|
||||
use reid_lib::{
|
||||
compile::CompiledModule,
|
||||
debug_information::{
|
||||
DebugFileData, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind,
|
||||
DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData,
|
||||
DwarfFlags, InstructionDebugRecordData,
|
||||
DebugFileData, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind, DebugSubprogramData,
|
||||
DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DwarfFlags, InstructionDebugRecordData,
|
||||
},
|
||||
CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module,
|
||||
NamedStruct, TerminatorKind as Term, Type,
|
||||
CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct,
|
||||
TerminatorKind as Term, Type,
|
||||
};
|
||||
use scope::*;
|
||||
|
||||
use crate::{
|
||||
mir::{
|
||||
self, implement::TypeCategory, pass::ScopeBinopKey, CustomTypeKey, FunctionDefinitionKind,
|
||||
NamedVariableRef, SourceModuleId, StructField, StructType, TypeDefinitionKind, TypeKind,
|
||||
WhileStatement,
|
||||
self, implement::TypeCategory, pass::ScopeBinopKey, CustomTypeKey, FunctionDefinitionKind, NamedVariableRef,
|
||||
SourceModuleId, StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
|
||||
},
|
||||
util::try_all,
|
||||
};
|
||||
@ -83,9 +81,7 @@ struct State {
|
||||
impl State {
|
||||
/// Sets should load, returning a new state
|
||||
fn load(self, should: bool) -> State {
|
||||
State {
|
||||
should_load: should,
|
||||
}
|
||||
State { should_load: should }
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,10 +231,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.1.get_type(&type_values), binop.rhs.1.get_type(&type_values)],
|
||||
FunctionFlags {
|
||||
inline: true,
|
||||
..Default::default()
|
||||
@ -287,9 +280,7 @@ impl mir::Module {
|
||||
&binop.return_type,
|
||||
&ir_function,
|
||||
match &binop.fn_kind {
|
||||
FunctionDefinitionKind::Local(_, meta) => {
|
||||
meta.into_debug(tokens, compile_unit)
|
||||
}
|
||||
FunctionDefinitionKind::Local(_, meta) => meta.into_debug(tokens, compile_unit),
|
||||
FunctionDefinitionKind::Extern(_) => None,
|
||||
FunctionDefinitionKind::Intrinsic(_) => None,
|
||||
},
|
||||
@ -352,9 +343,7 @@ impl mir::Module {
|
||||
&mir_function.return_type,
|
||||
&function,
|
||||
match &mir_function.kind {
|
||||
FunctionDefinitionKind::Local(..) => {
|
||||
mir_function.signature().into_debug(tokens, compile_unit)
|
||||
}
|
||||
FunctionDefinitionKind::Local(..) => mir_function.signature().into_debug(tokens, compile_unit),
|
||||
FunctionDefinitionKind::Extern(_) => None,
|
||||
FunctionDefinitionKind::Intrinsic(_) => None,
|
||||
},
|
||||
@ -386,13 +375,10 @@ impl FunctionDefinitionKind {
|
||||
|
||||
let fn_param_ty = &return_type.get_debug_type(&debug, scope);
|
||||
|
||||
let debug_ty =
|
||||
debug
|
||||
.info
|
||||
.debug_type(DebugTypeData::Subprogram(DebugSubprogramType {
|
||||
parameters: vec![*fn_param_ty],
|
||||
flags: DwarfFlags,
|
||||
}));
|
||||
let debug_ty = debug.info.debug_type(DebugTypeData::Subprogram(DebugSubprogramType {
|
||||
parameters: vec![*fn_param_ty],
|
||||
flags: DwarfFlags,
|
||||
}));
|
||||
|
||||
let subprogram = debug.info.subprogram(DebugSubprogramData {
|
||||
name: name.clone(),
|
||||
@ -477,9 +463,7 @@ impl FunctionDefinitionKind {
|
||||
}
|
||||
|
||||
if let Some(debug) = &scope.debug {
|
||||
if let Some(location) =
|
||||
&block.return_meta().into_debug(scope.tokens, debug.scope)
|
||||
{
|
||||
if let Some(location) = &block.return_meta().into_debug(scope.tokens, debug.scope) {
|
||||
let location = debug.info.location(&debug.scope, *location);
|
||||
scope.block.set_terminator_location(location).unwrap();
|
||||
}
|
||||
@ -536,11 +520,7 @@ impl mir::Block {
|
||||
}
|
||||
|
||||
impl mir::Statement {
|
||||
fn codegen<'ctx, 'a>(
|
||||
&self,
|
||||
scope: &mut Scope<'ctx, 'a>,
|
||||
state: &State,
|
||||
) -> Result<Option<StackValue>, ErrorKind> {
|
||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> {
|
||||
let location = scope.debug.clone().map(|d| {
|
||||
let location = self.1.into_debug(scope.tokens, d.scope).unwrap();
|
||||
d.info.location(&d.scope, location)
|
||||
@ -557,10 +537,7 @@ impl mir::Statement {
|
||||
|
||||
let store = scope
|
||||
.block
|
||||
.build_named(
|
||||
format!("{}.store", name),
|
||||
Instr::Store(alloca, value.instr()),
|
||||
)
|
||||
.build_named(format!("{}.store", name), Instr::Store(alloca, value.instr()))
|
||||
.unwrap()
|
||||
.maybe_location(&mut scope.block, location);
|
||||
|
||||
@ -632,17 +609,12 @@ impl mir::Statement {
|
||||
}
|
||||
mir::StmtKind::Import(_) => todo!(),
|
||||
mir::StmtKind::Expression(expression) => expression.codegen(scope, state),
|
||||
mir::StmtKind::While(WhileStatement {
|
||||
condition, block, ..
|
||||
}) => {
|
||||
mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
|
||||
let condition_block = scope.function.block("while.cond");
|
||||
let condition_true_block = scope.function.block("while.body");
|
||||
let condition_failed_block = scope.function.block("while.end");
|
||||
|
||||
scope
|
||||
.block
|
||||
.terminate(Term::Br(condition_block.value()))
|
||||
.unwrap();
|
||||
scope.block.terminate(Term::Br(condition_block.value())).unwrap();
|
||||
let mut condition_scope = scope.with_block(condition_block);
|
||||
let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap();
|
||||
let true_instr = condition_scope
|
||||
@ -651,11 +623,7 @@ impl mir::Statement {
|
||||
.unwrap();
|
||||
let check = condition_scope
|
||||
.block
|
||||
.build(Instr::ICmp(
|
||||
CmpPredicate::EQ,
|
||||
condition_res.instr(),
|
||||
true_instr,
|
||||
))
|
||||
.build(Instr::ICmp(CmpPredicate::EQ, condition_res.instr(), true_instr))
|
||||
.unwrap();
|
||||
|
||||
condition_scope
|
||||
@ -685,16 +653,13 @@ impl mir::Statement {
|
||||
}
|
||||
|
||||
impl mir::Expression {
|
||||
fn codegen<'ctx, 'a>(
|
||||
&self,
|
||||
scope: &mut Scope<'ctx, 'a>,
|
||||
state: &State,
|
||||
) -> Result<Option<StackValue>, ErrorKind> {
|
||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> {
|
||||
let location = if let Some(debug) = &scope.debug {
|
||||
Some(debug.info.location(
|
||||
&debug.scope,
|
||||
self.1.into_debug(scope.tokens, debug.scope).unwrap(),
|
||||
))
|
||||
Some(
|
||||
debug
|
||||
.info
|
||||
.location(&debug.scope, self.1.into_debug(scope.tokens, debug.scope).unwrap()),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -715,10 +680,7 @@ impl mir::Expression {
|
||||
.block
|
||||
.build_named(
|
||||
format!("{}", varref.1),
|
||||
Instr::Load(
|
||||
v.0.instr(),
|
||||
inner.get_type(scope.type_values),
|
||||
),
|
||||
Instr::Load(v.0.instr(), inner.get_type(scope.type_values)),
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
@ -736,13 +698,9 @@ impl mir::Expression {
|
||||
StackValueKind::Literal(lit.as_const(&mut scope.block)),
|
||||
lit.as_type(),
|
||||
)),
|
||||
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
||||
let lhs_val = lhs_exp
|
||||
.codegen(scope, state)?
|
||||
.expect("lhs has no return value");
|
||||
let rhs_val = rhs_exp
|
||||
.codegen(scope, state)?
|
||||
.expect("rhs has no return value");
|
||||
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp, return_ty) => {
|
||||
let lhs_val = lhs_exp.codegen(scope, state)?.expect("lhs has no return value");
|
||||
let rhs_val = rhs_exp.codegen(scope, state)?.expect("rhs has no return value");
|
||||
let lhs = lhs_val.instr();
|
||||
let rhs = rhs_val.instr();
|
||||
|
||||
@ -755,15 +713,8 @@ impl mir::Expression {
|
||||
let a = operation.codegen(&lhs_val, &rhs_val, scope)?;
|
||||
Some(a)
|
||||
} else {
|
||||
let lhs_type = lhs_exp
|
||||
.return_type(&Default::default(), scope.module_id)
|
||||
.unwrap()
|
||||
.1;
|
||||
let instr = match (
|
||||
binop,
|
||||
lhs_type.signed(),
|
||||
lhs_type.category() == TypeCategory::Real,
|
||||
) {
|
||||
let lhs_type = lhs_exp.return_type(&Default::default(), scope.module_id).unwrap().1;
|
||||
let instr = match (binop, lhs_type.signed(), lhs_type.category() == TypeCategory::Real) {
|
||||
(mir::BinaryOperator::Add, _, false) => Instr::Add(lhs, rhs),
|
||||
(mir::BinaryOperator::Add, _, true) => Instr::FAdd(lhs, rhs),
|
||||
(mir::BinaryOperator::Minus, _, false) => Instr::Sub(lhs, rhs),
|
||||
@ -771,12 +722,8 @@ impl mir::Expression {
|
||||
(mir::BinaryOperator::Mult, _, false) => Instr::Mul(lhs, rhs),
|
||||
(mir::BinaryOperator::Mult, _, true) => Instr::FMul(lhs, rhs),
|
||||
(mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs),
|
||||
(mir::BinaryOperator::Cmp(i), _, false) => {
|
||||
Instr::ICmp(i.predicate(), lhs, rhs)
|
||||
}
|
||||
(mir::BinaryOperator::Cmp(i), _, true) => {
|
||||
Instr::FCmp(i.predicate(), lhs, rhs)
|
||||
}
|
||||
(mir::BinaryOperator::Cmp(i), _, false) => Instr::ICmp(i.predicate(), lhs, rhs),
|
||||
(mir::BinaryOperator::Cmp(i), _, true) => Instr::FCmp(i.predicate(), lhs, rhs),
|
||||
(mir::BinaryOperator::Div, false, false) => Instr::UDiv(lhs, rhs),
|
||||
(mir::BinaryOperator::Div, true, false) => Instr::SDiv(lhs, rhs),
|
||||
(mir::BinaryOperator::Div, _, true) => Instr::FDiv(lhs, rhs),
|
||||
@ -828,15 +775,12 @@ impl mir::Expression {
|
||||
.unwrap()
|
||||
.maybe_location(&mut scope.block, location),
|
||||
),
|
||||
lhs_type,
|
||||
return_ty.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
mir::ExprKind::FunctionCall(call) => {
|
||||
let ret_type_kind = call
|
||||
.return_type
|
||||
.known()
|
||||
.expect("function return type unknown");
|
||||
let ret_type_kind = call.return_type.known().expect("function return type unknown");
|
||||
|
||||
let ret_type = ret_type_kind.get_type(scope.type_values);
|
||||
|
||||
@ -852,17 +796,11 @@ impl mir::Expression {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let param_instrs = params.iter().map(|e| e.instr()).collect();
|
||||
let callee = scope
|
||||
.functions
|
||||
.get(&call.name)
|
||||
.expect("function not found!");
|
||||
let callee = scope.functions.get(&call.name).expect("function not found!");
|
||||
|
||||
let val = scope
|
||||
.block
|
||||
.build_named(
|
||||
call.name.clone(),
|
||||
Instr::FunctionCall(callee.value(), param_instrs),
|
||||
)
|
||||
.build_named(call.name.clone(), Instr::FunctionCall(callee.value(), param_instrs))
|
||||
.unwrap();
|
||||
|
||||
if let Some(debug) = &scope.debug {
|
||||
@ -939,10 +877,7 @@ impl mir::Expression {
|
||||
let (ptr, contained_ty) = if let TypeKind::UserPtr(further_inner) = *inner.clone() {
|
||||
let loaded = scope
|
||||
.block
|
||||
.build_named(
|
||||
"load",
|
||||
Instr::Load(kind.instr(), inner.get_type(scope.type_values)),
|
||||
)
|
||||
.build_named("load", Instr::Load(kind.instr(), inner.get_type(scope.type_values)))
|
||||
.unwrap();
|
||||
(
|
||||
scope
|
||||
@ -960,10 +895,7 @@ impl mir::Expression {
|
||||
(
|
||||
scope
|
||||
.block
|
||||
.build_named(
|
||||
format!("array.gep"),
|
||||
Instr::GetElemPtr(kind.instr(), vec![idx]),
|
||||
)
|
||||
.build_named(format!("array.gep"), Instr::GetElemPtr(kind.instr(), vec![idx]))
|
||||
.unwrap()
|
||||
.maybe_location(&mut scope.block, location),
|
||||
val_t.clone(),
|
||||
@ -980,10 +912,7 @@ impl mir::Expression {
|
||||
(
|
||||
scope
|
||||
.block
|
||||
.build_named(
|
||||
format!("array.gep"),
|
||||
Instr::GetElemPtr(kind.instr(), vec![first, idx]),
|
||||
)
|
||||
.build_named(format!("array.gep"), Instr::GetElemPtr(kind.instr(), vec![first, idx]))
|
||||
.unwrap()
|
||||
.maybe_location(&mut scope.block, location),
|
||||
val_t.clone(),
|
||||
@ -995,10 +924,7 @@ impl mir::Expression {
|
||||
kind.derive(
|
||||
scope
|
||||
.block
|
||||
.build_named(
|
||||
"array.load",
|
||||
Instr::Load(ptr, contained_ty.get_type(scope.type_values)),
|
||||
)
|
||||
.build_named("array.load", Instr::Load(ptr, contained_ty.get_type(scope.type_values)))
|
||||
.unwrap()
|
||||
.maybe_location(&mut scope.block, location),
|
||||
),
|
||||
@ -1012,21 +938,14 @@ impl mir::Expression {
|
||||
}
|
||||
}
|
||||
mir::ExprKind::Array(expressions) => {
|
||||
let stack_value_list: Vec<_> = try_all(
|
||||
expressions
|
||||
.iter()
|
||||
.map(|e| e.codegen(scope, state))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.map_err(|e| e.first().cloned().unwrap())?
|
||||
.into_iter()
|
||||
.map(|v| v.unwrap())
|
||||
.collect();
|
||||
let stack_value_list: Vec<_> =
|
||||
try_all(expressions.iter().map(|e| e.codegen(scope, state)).collect::<Vec<_>>())
|
||||
.map_err(|e| e.first().cloned().unwrap())?
|
||||
.into_iter()
|
||||
.map(|v| v.unwrap())
|
||||
.collect();
|
||||
|
||||
let instr_list = stack_value_list
|
||||
.iter()
|
||||
.map(|s| s.instr())
|
||||
.collect::<Vec<_>>();
|
||||
let instr_list = stack_value_list.iter().map(|s| s.instr()).collect::<Vec<_>>();
|
||||
|
||||
let elem_ty_kind = stack_value_list
|
||||
.iter()
|
||||
@ -1053,10 +972,7 @@ impl mir::Expression {
|
||||
|
||||
let index_expr = scope
|
||||
.block
|
||||
.build_named(
|
||||
index.to_string(),
|
||||
Instr::Constant(ConstValue::U32(index as u32)),
|
||||
)
|
||||
.build_named(index.to_string(), Instr::Constant(ConstValue::U32(index as u32)))
|
||||
.unwrap();
|
||||
let first = scope
|
||||
.block
|
||||
@ -1094,8 +1010,7 @@ impl mir::Expression {
|
||||
let TypeKind::CustomType(key) = *inner.clone() else {
|
||||
panic!("tried accessing non-custom-type");
|
||||
};
|
||||
let TypeDefinitionKind::Struct(struct_ty) =
|
||||
scope.get_typedef(&key).unwrap().kind.clone();
|
||||
let TypeDefinitionKind::Struct(struct_ty) = scope.get_typedef(&key).unwrap().kind.clone();
|
||||
let idx = struct_ty.find_index(field).unwrap();
|
||||
|
||||
let gep_n = format!("{}.{}.gep", key.0, field);
|
||||
@ -1103,10 +1018,7 @@ impl mir::Expression {
|
||||
|
||||
let value = scope
|
||||
.block
|
||||
.build_named(
|
||||
gep_n,
|
||||
Instr::GetStructElemPtr(struct_val.instr(), idx as u32),
|
||||
)
|
||||
.build_named(gep_n, Instr::GetStructElemPtr(struct_val.instr(), idx as u32))
|
||||
.unwrap();
|
||||
|
||||
// value.maybe_location(&mut scope.block, location);
|
||||
@ -1116,10 +1028,7 @@ impl mir::Expression {
|
||||
struct_val.0.derive(
|
||||
scope
|
||||
.block
|
||||
.build_named(
|
||||
load_n,
|
||||
Instr::Load(value, type_kind.get_type(scope.type_values)),
|
||||
)
|
||||
.build_named(load_n, Instr::Load(value, type_kind.get_type(scope.type_values)))
|
||||
.unwrap(),
|
||||
),
|
||||
struct_ty.get_field_ty(&field).unwrap().clone(),
|
||||
@ -1127,32 +1036,38 @@ impl mir::Expression {
|
||||
} else {
|
||||
Some(StackValue(
|
||||
struct_val.0.derive(value),
|
||||
TypeKind::CodegenPtr(Box::new(
|
||||
struct_ty.get_field_ty(&field).unwrap().clone(),
|
||||
)),
|
||||
TypeKind::CodegenPtr(Box::new(struct_ty.get_field_ty(&field).unwrap().clone())),
|
||||
))
|
||||
}
|
||||
}
|
||||
mir::ExprKind::Struct(name, items) => {
|
||||
let type_key = CustomTypeKey(name.clone(), scope.module_id);
|
||||
let struct_ty = Type::CustomType({
|
||||
let ty = Type::CustomType({
|
||||
let Some(a) = scope.type_values.get(&type_key) else {
|
||||
return Ok(None);
|
||||
};
|
||||
*a
|
||||
});
|
||||
|
||||
let TypeDefinition {
|
||||
kind: TypeDefinitionKind::Struct(struct_ty),
|
||||
..
|
||||
} = scope.types.get(scope.type_values.get(&type_key).unwrap()).unwrap();
|
||||
|
||||
let indices = struct_ty.0.iter().enumerate();
|
||||
|
||||
let load_n = format!("{}.load", name);
|
||||
|
||||
let struct_ptr = scope
|
||||
.block
|
||||
.build_named(name, Instr::Alloca(struct_ty.clone()))
|
||||
.build_named(name, Instr::Alloca(ty.clone()))
|
||||
.unwrap()
|
||||
.maybe_location(&mut scope.block, location);
|
||||
|
||||
for (i, (field_n, exp)) in items.iter().enumerate() {
|
||||
for (field_n, exp) in items {
|
||||
let gep_n = format!("{}.{}.gep", name, field_n);
|
||||
let store_n = format!("{}.{}.store", name, field_n);
|
||||
let i = indices.clone().find(|(_, f)| f.0 == *field_n).unwrap().0;
|
||||
|
||||
let elem_ptr = scope
|
||||
.block
|
||||
@ -1168,10 +1083,7 @@ impl mir::Expression {
|
||||
}
|
||||
}
|
||||
|
||||
let struct_val = scope
|
||||
.block
|
||||
.build_named(load_n, Instr::Load(struct_ptr, struct_ty))
|
||||
.unwrap();
|
||||
let struct_val = scope.block.build_named(load_n, Instr::Load(struct_ptr, ty)).unwrap();
|
||||
|
||||
Some(StackValue(
|
||||
StackValueKind::Literal(struct_val),
|
||||
@ -1222,10 +1134,7 @@ impl mir::Expression {
|
||||
.block
|
||||
.build_named(
|
||||
format!("{}.deref.inner", varref.1),
|
||||
Instr::Load(
|
||||
var_ptr_instr,
|
||||
inner.get_type(scope.type_values),
|
||||
),
|
||||
Instr::Load(var_ptr_instr, inner.get_type(scope.type_values)),
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
@ -1253,17 +1162,14 @@ impl mir::Expression {
|
||||
Some(val)
|
||||
} else {
|
||||
match (&val.1, type_kind) {
|
||||
(TypeKind::CodegenPtr(inner), TypeKind::UserPtr(_)) => match *inner.clone()
|
||||
{
|
||||
(TypeKind::CodegenPtr(inner), TypeKind::UserPtr(_)) => match *inner.clone() {
|
||||
TypeKind::UserPtr(_) => Some(StackValue(
|
||||
val.0.derive(
|
||||
scope
|
||||
.block
|
||||
.build(Instr::BitCast(
|
||||
val.instr(),
|
||||
Type::Ptr(Box::new(
|
||||
type_kind.get_type(scope.type_values),
|
||||
)),
|
||||
Type::Ptr(Box::new(type_kind.get_type(scope.type_values))),
|
||||
))
|
||||
.unwrap(),
|
||||
),
|
||||
@ -1278,10 +1184,7 @@ impl mir::Expression {
|
||||
val.0.derive(
|
||||
scope
|
||||
.block
|
||||
.build(Instr::BitCast(
|
||||
val.instr(),
|
||||
type_kind.get_type(scope.type_values),
|
||||
))
|
||||
.build(Instr::BitCast(val.instr(), type_kind.get_type(scope.type_values)))
|
||||
.unwrap(),
|
||||
),
|
||||
type_kind.clone(),
|
||||
@ -1290,10 +1193,7 @@ impl mir::Expression {
|
||||
let cast_instr = val
|
||||
.1
|
||||
.get_type(scope.type_values)
|
||||
.cast_instruction(
|
||||
val.instr(),
|
||||
&type_kind.get_type(scope.type_values),
|
||||
)
|
||||
.cast_instruction(val.instr(), &type_kind.get_type(scope.type_values))
|
||||
.unwrap();
|
||||
|
||||
Some(StackValue(
|
||||
@ -1313,11 +1213,7 @@ impl mir::Expression {
|
||||
}
|
||||
|
||||
impl mir::IfExpression {
|
||||
fn codegen<'ctx, 'a>(
|
||||
&self,
|
||||
scope: &mut Scope<'ctx, 'a>,
|
||||
state: &State,
|
||||
) -> Result<Option<StackValue>, ErrorKind> {
|
||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> {
|
||||
let condition = self.0.codegen(scope, state)?.unwrap();
|
||||
|
||||
// Create blocks
|
||||
@ -1389,10 +1285,7 @@ impl mir::IfExpression {
|
||||
incoming.extend(else_res.clone());
|
||||
let instr = scope
|
||||
.block
|
||||
.build_named(
|
||||
"phi",
|
||||
Instr::Phi(incoming.iter().map(|i| i.instr()).collect()),
|
||||
)
|
||||
.build_named("phi", Instr::Phi(incoming.iter().map(|i| i.instr()).collect()))
|
||||
.unwrap();
|
||||
|
||||
use StackValueKind::*;
|
||||
|
@ -160,9 +160,7 @@ impl<'ctx> StackBinopDefinition<'ctx> {
|
||||
self.return_ty.clone(),
|
||||
))
|
||||
}
|
||||
StackBinopFunctionKind::Intrinsic(fun) => {
|
||||
fun.codegen(scope, &[lhs.instr(), rhs.instr()])
|
||||
}
|
||||
StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@
|
||||
//! - Debug Symbols
|
||||
//! ```
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::{path::PathBuf, thread, time::Duration};
|
||||
|
||||
use ast::{
|
||||
lexer::{self, FullToken, Token},
|
||||
@ -51,6 +51,7 @@ use codegen::intrinsics::{form_intrinsic_binops, form_intrinsics};
|
||||
use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError};
|
||||
use mir::{
|
||||
linker::LinkerPass,
|
||||
pass::BinopMap,
|
||||
typecheck::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs},
|
||||
};
|
||||
use reid_lib::{compile::CompileOutput, Context};
|
||||
@ -97,11 +98,7 @@ pub fn compile_module<'map>(
|
||||
let mut statements = Vec::new();
|
||||
|
||||
while !matches!(token_stream.peek().unwrap_or(Token::Eof), Token::Eof) {
|
||||
let statement = ReidError::from_parser(
|
||||
token_stream.parse::<TopLevelStatement>(),
|
||||
map.clone(),
|
||||
module_id,
|
||||
)?;
|
||||
let statement = ReidError::from_parser(token_stream.parse::<TopLevelStatement>(), map.clone(), module_id)?;
|
||||
statements.push(statement);
|
||||
}
|
||||
|
||||
@ -128,8 +125,22 @@ pub fn perform_all_passes<'map>(
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&context);
|
||||
|
||||
let mut binops = BinopMap::default();
|
||||
for module in &mut context.modules {
|
||||
for intrinsic in form_intrinsic_binops() {
|
||||
binops
|
||||
.set(
|
||||
mir::pass::ScopeBinopKey {
|
||||
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||
operator: intrinsic.op,
|
||||
},
|
||||
mir::pass::ScopeBinopDef {
|
||||
hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||
operator: intrinsic.op,
|
||||
return_ty: intrinsic.return_type.clone(),
|
||||
},
|
||||
)
|
||||
.ok();
|
||||
module.1.binop_defs.insert(0, intrinsic);
|
||||
}
|
||||
}
|
||||
@ -141,7 +152,7 @@ pub fn perform_all_passes<'map>(
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &context);
|
||||
println!("{:#}", &context);
|
||||
|
||||
let state = context.pass(&mut LinkerPass {
|
||||
module_map,
|
||||
@ -151,7 +162,7 @@ pub fn perform_all_passes<'map>(
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{:-^100}", "LINKER OUTPUT");
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &context);
|
||||
println!("{:#}", &context);
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&state);
|
||||
|
||||
@ -162,7 +173,7 @@ pub fn perform_all_passes<'map>(
|
||||
));
|
||||
}
|
||||
|
||||
let refs = TypeRefs::default();
|
||||
let refs = TypeRefs::with_binops(binops);
|
||||
|
||||
let state = context.pass(&mut TypeInference { refs: &refs })?;
|
||||
|
||||
@ -171,7 +182,7 @@ pub fn perform_all_passes<'map>(
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &refs);
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &context);
|
||||
println!("{:#}", &context);
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&state);
|
||||
|
||||
@ -191,7 +202,7 @@ pub fn perform_all_passes<'map>(
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{:-^100}", "TYPECHECKER OUTPUT");
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &context);
|
||||
println!("{:#}", &context);
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&state);
|
||||
|
||||
@ -232,7 +243,7 @@ pub fn compile_and_pass<'map>(
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{:-^100}", "FINAL OUTPUT");
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &mir_context);
|
||||
println!("{:#}", &mir_context);
|
||||
|
||||
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
|
||||
let codegen_modules = match mir_context.codegen(&mut context) {
|
||||
|
@ -15,6 +15,8 @@ impl Display for Context {
|
||||
|
||||
impl Display for Module {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let is_alternate = f.alternate();
|
||||
|
||||
writeln!(f, "Module({}) ({}) {{", self.name, self.module_id)?;
|
||||
|
||||
let mut state = Default::default();
|
||||
@ -23,9 +25,27 @@ impl Display for Module {
|
||||
for import in &self.imports {
|
||||
writeln!(inner_f, "{}", import)?;
|
||||
}
|
||||
for binop in &self.binop_defs {
|
||||
|
||||
let intrinsic_binops = self
|
||||
.binop_defs
|
||||
.iter()
|
||||
.filter(|b| matches!(b.fn_kind, FunctionDefinitionKind::Intrinsic(_)));
|
||||
|
||||
for binop in self
|
||||
.binop_defs
|
||||
.iter()
|
||||
.filter(|b| !matches!(b.fn_kind, FunctionDefinitionKind::Intrinsic(_)))
|
||||
{
|
||||
writeln!(inner_f, "{}", binop)?;
|
||||
}
|
||||
|
||||
if is_alternate {
|
||||
writeln!(inner_f, "... <{}> intrinsic binary operators", intrinsic_binops.count())?;
|
||||
} else {
|
||||
for binop in intrinsic_binops {
|
||||
writeln!(inner_f, "{}", binop)?;
|
||||
}
|
||||
}
|
||||
for typedef in &self.typedefs {
|
||||
writeln!(inner_f, "{}", typedef)?;
|
||||
}
|
||||
@ -152,24 +172,14 @@ impl Display for StmtKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
StmtKind::Let(var, mutable, block) => {
|
||||
write!(
|
||||
f,
|
||||
"let{} {} = {}",
|
||||
if *mutable { " mut" } else { "" },
|
||||
var,
|
||||
block
|
||||
)
|
||||
write!(f, "let{} {} = {}", if *mutable { " mut" } else { "" }, var, block)
|
||||
}
|
||||
StmtKind::Set(var, expr) => write!(f, "{} = {}", var, expr),
|
||||
StmtKind::Import(n) => write!(f, "import {}", n),
|
||||
StmtKind::Expression(exp) => Display::fmt(exp, f),
|
||||
|
||||
StmtKind::While(while_statement) => {
|
||||
write!(
|
||||
f,
|
||||
"while {} {}",
|
||||
while_statement.condition, while_statement.block,
|
||||
)
|
||||
write!(f, "while {} {}", while_statement.condition, while_statement.block,)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -189,7 +199,12 @@ impl Display for ExprKind {
|
||||
match self {
|
||||
ExprKind::Variable(var) => Display::fmt(var, f),
|
||||
ExprKind::Literal(lit) => Display::fmt(lit, f),
|
||||
ExprKind::BinOp(op, lhs, rhs) => write!(f, "{} {} {}", lhs, op, rhs),
|
||||
ExprKind::BinOp(op, lhs, rhs, ty) => {
|
||||
write!(f, "{} {} {} (= ", lhs, op, rhs)?;
|
||||
Debug::fmt(ty, f)?;
|
||||
f.write_char(')')?;
|
||||
Ok(())
|
||||
}
|
||||
ExprKind::FunctionCall(fc) => Display::fmt(fc, f),
|
||||
ExprKind::If(if_exp) => Display::fmt(&if_exp, f),
|
||||
ExprKind::Block(block) => Display::fmt(block, f),
|
||||
|
@ -43,20 +43,6 @@ impl TypeKind {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn binop_type(
|
||||
lhs: &TypeKind,
|
||||
rhs: &TypeKind,
|
||||
binop: &ScopeBinopDef,
|
||||
) -> Option<(TypeKind, TypeKind, TypeKind)> {
|
||||
let lhs_ty = lhs.narrow_into(&binop.hands.0);
|
||||
let rhs_ty = rhs.narrow_into(&binop.hands.1);
|
||||
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
|
||||
Some((lhs_ty, rhs_ty, binop.return_ty.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Reverse of binop_type, where the given hint is the known required output
|
||||
/// type of the binop, and the output is the hint for the lhs/rhs type.
|
||||
pub fn simple_binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> {
|
||||
@ -373,10 +359,7 @@ impl Statement {
|
||||
expr.return_type(refs, mod_id)?,
|
||||
Err(ReturnTypeOther::Let(var.2 + expr.1)),
|
||||
),
|
||||
Set(lhs, rhs) => if_hard(
|
||||
rhs.return_type(refs, mod_id)?,
|
||||
Err(ReturnTypeOther::Set(lhs.1 + rhs.1)),
|
||||
),
|
||||
Set(lhs, rhs) => if_hard(rhs.return_type(refs, mod_id)?, Err(ReturnTypeOther::Set(lhs.1 + rhs.1))),
|
||||
Import(_) => todo!(),
|
||||
Expression(expression) => expression.return_type(refs, mod_id),
|
||||
While(_) => Err(ReturnTypeOther::Loop),
|
||||
@ -404,11 +387,14 @@ impl Expression {
|
||||
match &self.0 {
|
||||
Literal(lit) => Ok((ReturnKind::Soft, lit.as_type())),
|
||||
Variable(var) => var.return_type(),
|
||||
BinOp(_, then_e, else_e) => {
|
||||
BinOp(_, then_e, else_e, return_ty) => {
|
||||
let then_r = then_e.return_type(refs, mod_id)?;
|
||||
let else_r = else_e.return_type(refs, mod_id)?;
|
||||
|
||||
Ok(pick_return(then_r, else_r))
|
||||
Ok(match (then_r.0, else_r.0) {
|
||||
(ReturnKind::Hard, ReturnKind::Hard) => (ReturnKind::Hard, return_ty.clone()),
|
||||
_ => (ReturnKind::Soft, return_ty.clone()),
|
||||
})
|
||||
}
|
||||
Block(block) => block.return_type(refs, mod_id),
|
||||
FunctionCall(fcall) => fcall.return_type(),
|
||||
@ -471,7 +457,7 @@ impl Expression {
|
||||
ExprKind::Array(_) => None,
|
||||
ExprKind::Struct(_, _) => None,
|
||||
ExprKind::Literal(_) => None,
|
||||
ExprKind::BinOp(_, _, _) => None,
|
||||
ExprKind::BinOp(_, _, _, _) => None,
|
||||
ExprKind::FunctionCall(_) => None,
|
||||
ExprKind::If(_) => None,
|
||||
ExprKind::CastTo(expression, _) => expression.backing_var(),
|
||||
@ -486,7 +472,7 @@ impl Expression {
|
||||
ExprKind::Array(_) => None,
|
||||
ExprKind::Struct(..) => None,
|
||||
ExprKind::Literal(literal) => literal.num_value(),
|
||||
ExprKind::BinOp(op, lhs, rhs) => match op {
|
||||
ExprKind::BinOp(op, lhs, rhs, _) => match op {
|
||||
BinaryOperator::Add => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a + b),
|
||||
BinaryOperator::Minus => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a - b),
|
||||
BinaryOperator::Mult => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a * b),
|
||||
@ -618,9 +604,7 @@ pub enum EqualsIssue {
|
||||
impl FunctionDefinition {
|
||||
pub fn equals_as_imported(&self, other: &FunctionDefinition) -> Result<(), EqualsIssue> {
|
||||
match &self.kind {
|
||||
FunctionDefinitionKind::Local(_, metadata) => {
|
||||
Err(EqualsIssue::ExistsLocally(*metadata))
|
||||
}
|
||||
FunctionDefinitionKind::Local(_, metadata) => Err(EqualsIssue::ExistsLocally(*metadata)),
|
||||
FunctionDefinitionKind::Extern(imported) => {
|
||||
if *imported {
|
||||
Err(EqualsIssue::ConflictWithImport(self.name.clone()))
|
||||
@ -632,10 +616,7 @@ impl FunctionDefinition {
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(EqualsIssue::AlreadyExtern(
|
||||
self.name.clone(),
|
||||
self.signature(),
|
||||
))
|
||||
Err(EqualsIssue::AlreadyExtern(self.name.clone(), self.signature()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ pub enum ExprKind {
|
||||
Array(Vec<Expression>),
|
||||
Struct(String, Vec<(String, Expression)>),
|
||||
Literal(Literal),
|
||||
BinOp(BinaryOperator, Box<Expression>, Box<Expression>),
|
||||
BinOp(BinaryOperator, Box<Expression>, Box<Expression>, TypeKind),
|
||||
FunctionCall(FunctionCall),
|
||||
If(IfExpression),
|
||||
Block(Block),
|
||||
@ -270,11 +270,7 @@ pub struct Expression(pub ExprKind, pub Metadata);
|
||||
|
||||
/// Condition, Then, Else
|
||||
#[derive(Debug)]
|
||||
pub struct IfExpression(
|
||||
pub Box<Expression>,
|
||||
pub Box<Expression>,
|
||||
pub Box<Option<Expression>>,
|
||||
);
|
||||
pub struct IfExpression(pub Box<Expression>, pub Box<Expression>, pub Box<Option<Expression>>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionCall {
|
||||
|
@ -5,6 +5,7 @@ use std::collections::HashMap;
|
||||
use std::convert::Infallible;
|
||||
use std::error::Error as STDError;
|
||||
|
||||
use crate::codegen::intrinsics::form_intrinsic_binops;
|
||||
use crate::error_raporting::ReidError;
|
||||
|
||||
use super::*;
|
||||
@ -53,12 +54,7 @@ impl<TErr: STDError> State<TErr> {
|
||||
}
|
||||
}
|
||||
|
||||
fn or_else<U, T: Into<Metadata> + Clone + Copy>(
|
||||
&mut self,
|
||||
result: Result<U, TErr>,
|
||||
default: U,
|
||||
meta: T,
|
||||
) -> U {
|
||||
fn or_else<U, T: Into<Metadata> + Clone + Copy>(&mut self, result: Result<U, TErr>, default: U, meta: T) -> U {
|
||||
match result {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
@ -71,11 +67,7 @@ impl<TErr: STDError> State<TErr> {
|
||||
}
|
||||
}
|
||||
|
||||
fn ok<T: Into<Metadata> + Clone + Copy, U>(
|
||||
&mut self,
|
||||
result: Result<U, TErr>,
|
||||
meta: T,
|
||||
) -> Option<U> {
|
||||
fn ok<T: Into<Metadata> + Clone + Copy, U>(&mut self, result: Result<U, TErr>, meta: T) -> Option<U> {
|
||||
match result {
|
||||
Ok(v) => Some(v),
|
||||
Err(e) => {
|
||||
@ -119,6 +111,10 @@ impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> {
|
||||
pub fn find(&self, key: &Key) -> Option<(&Key, &T)> {
|
||||
self.0.iter().find(|(k, _)| *k == key)
|
||||
}
|
||||
|
||||
pub fn filter(&self, key: &Key) -> Vec<(&Key, &T)> {
|
||||
self.0.iter().filter(|(k, _)| *k == key).collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub type BinopMap = Storage<ScopeBinopKey, ScopeBinopDef>;
|
||||
@ -195,8 +191,12 @@ impl PartialEq for ScopeBinopKey {
|
||||
if self.operator.is_commutative() != other.operator.is_commutative() {
|
||||
return false;
|
||||
}
|
||||
let operators_eq = self.params == other.params;
|
||||
let swapped_ops_eq = (self.params.1.clone(), self.params.0.clone()) == other.params;
|
||||
|
||||
let operators_eq =
|
||||
self.params.0.narrow_into(&other.params.0).is_ok() && self.params.1.narrow_into(&other.params.1).is_ok();
|
||||
let swapped_ops_eq =
|
||||
self.params.0.narrow_into(&other.params.1).is_ok() && self.params.1.narrow_into(&other.params.0).is_ok();
|
||||
|
||||
if self.operator.is_commutative() {
|
||||
operators_eq || swapped_ops_eq
|
||||
} else {
|
||||
@ -226,27 +226,11 @@ pub struct ScopeBinopDef {
|
||||
}
|
||||
|
||||
impl ScopeBinopDef {
|
||||
pub fn binop_hint_old(
|
||||
&self,
|
||||
lhs: &TypeKind,
|
||||
rhs: &TypeKind,
|
||||
ret_ty: &TypeKind,
|
||||
) -> Option<(TypeKind, TypeKind)> {
|
||||
ret_ty.narrow_into(&self.return_ty).ok()?;
|
||||
pub fn narrow(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option<(TypeKind, TypeKind, TypeKind)> {
|
||||
let lhs_ty = lhs.narrow_into(&self.hands.0);
|
||||
let rhs_ty = rhs.narrow_into(&self.hands.1);
|
||||
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
|
||||
Some((lhs_ty, rhs_ty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn binop_ret_ty(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option<TypeKind> {
|
||||
let lhs_ty = lhs.narrow_into(&self.hands.0);
|
||||
let rhs_ty = rhs.narrow_into(&self.hands.1);
|
||||
if let (Ok(_), Ok(_)) = (lhs_ty, rhs_ty) {
|
||||
Some(self.return_ty.clone())
|
||||
Some((lhs_ty, rhs_ty, self.return_ty.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -261,11 +245,7 @@ pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone>
|
||||
}
|
||||
|
||||
impl<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> PassState<'st, 'sc, Data, TError> {
|
||||
fn from(
|
||||
state: &'st mut State<TError>,
|
||||
scope: &'sc mut Scope<Data>,
|
||||
module_id: Option<SourceModuleId>,
|
||||
) -> Self {
|
||||
fn from(state: &'st mut State<TError>, scope: &'sc mut Scope<Data>, module_id: Option<SourceModuleId>) -> Self {
|
||||
PassState {
|
||||
state,
|
||||
scope,
|
||||
@ -283,19 +263,11 @@ impl<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> PassState<'st, '
|
||||
self.state.or_else(result, default, meta)
|
||||
}
|
||||
|
||||
pub fn ok<TMeta: Into<Metadata> + Clone + Copy, U>(
|
||||
&mut self,
|
||||
result: Result<U, TError>,
|
||||
meta: TMeta,
|
||||
) -> Option<U> {
|
||||
pub fn ok<TMeta: Into<Metadata> + Clone + Copy, U>(&mut self, result: Result<U, TError>, meta: TMeta) -> Option<U> {
|
||||
self.state.ok(result, meta)
|
||||
}
|
||||
|
||||
pub fn note_errors<TMeta: Into<Metadata> + Clone>(
|
||||
&mut self,
|
||||
errors: &Vec<TError>,
|
||||
meta: TMeta,
|
||||
) {
|
||||
pub fn note_errors<TMeta: Into<Metadata> + Clone>(&mut self, errors: &Vec<TError>, meta: TMeta) {
|
||||
for error in errors {
|
||||
self.ok::<_, Infallible>(Err(error.clone()), meta.clone().into());
|
||||
}
|
||||
@ -319,18 +291,10 @@ pub trait Pass {
|
||||
type Data: Clone + Default;
|
||||
type TError: STDError + Clone;
|
||||
|
||||
fn context(
|
||||
&mut self,
|
||||
_context: &mut Context,
|
||||
mut _state: PassState<Self::Data, Self::TError>,
|
||||
) -> PassResult {
|
||||
fn context(&mut self, _context: &mut Context, mut _state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||
Ok(())
|
||||
}
|
||||
fn module(
|
||||
&mut self,
|
||||
_module: &mut Module,
|
||||
mut _state: PassState<Self::Data, Self::TError>,
|
||||
) -> PassResult {
|
||||
fn module(&mut self, _module: &mut Module, mut _state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||
Ok(())
|
||||
}
|
||||
fn function(
|
||||
@ -340,25 +304,13 @@ pub trait Pass {
|
||||
) -> PassResult {
|
||||
Ok(())
|
||||
}
|
||||
fn block(
|
||||
&mut self,
|
||||
_block: &mut Block,
|
||||
mut _state: PassState<Self::Data, Self::TError>,
|
||||
) -> PassResult {
|
||||
fn block(&mut self, _block: &mut Block, mut _state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||
Ok(())
|
||||
}
|
||||
fn stmt(
|
||||
&mut self,
|
||||
_stmt: &mut Statement,
|
||||
mut _state: PassState<Self::Data, Self::TError>,
|
||||
) -> PassResult {
|
||||
fn stmt(&mut self, _stmt: &mut Statement, mut _state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||
Ok(())
|
||||
}
|
||||
fn expr(
|
||||
&mut self,
|
||||
_expr: &mut Expression,
|
||||
mut _state: PassState<Self::Data, Self::TError>,
|
||||
) -> PassResult {
|
||||
fn expr(&mut self, _expr: &mut Expression, mut _state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -368,6 +320,24 @@ impl Context {
|
||||
let mut state = State::new();
|
||||
let mut scope = Scope::default();
|
||||
pass.context(self, PassState::from(&mut state, &mut scope, None))?;
|
||||
|
||||
for intrinsic in form_intrinsic_binops() {
|
||||
scope
|
||||
.binops
|
||||
.set(
|
||||
ScopeBinopKey {
|
||||
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||
operator: intrinsic.op,
|
||||
},
|
||||
ScopeBinopDef {
|
||||
hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||
operator: intrinsic.op,
|
||||
return_ty: intrinsic.return_type.clone(),
|
||||
},
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
|
||||
for (_, module) in &mut self.modules {
|
||||
module.pass(pass, &mut state, &mut scope.inner())?;
|
||||
}
|
||||
@ -376,12 +346,7 @@ impl Context {
|
||||
}
|
||||
|
||||
impl Module {
|
||||
fn pass<T: Pass>(
|
||||
&mut self,
|
||||
pass: &mut T,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
) -> PassResult {
|
||||
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope<T::Data>) -> PassResult {
|
||||
for typedef in &self.typedefs {
|
||||
scope
|
||||
.types
|
||||
|
@ -50,6 +50,8 @@ pub enum ErrorKind {
|
||||
TriedAccessingNonStruct(TypeKind),
|
||||
#[error("No such struct-field on type {0}")]
|
||||
NoSuchField(String),
|
||||
#[error("Missing definition for field \"{0}\"")]
|
||||
MissingStructField(String),
|
||||
#[error("Struct field declared twice {0}")]
|
||||
DuplicateStructField(String),
|
||||
#[error("Type declared twice {0}")]
|
||||
@ -78,6 +80,34 @@ pub enum ErrorKind {
|
||||
InvalidBinop(BinaryOperator, TypeKind, TypeKind),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum HintKind {
|
||||
Coerce(TypeKind),
|
||||
Default,
|
||||
None,
|
||||
}
|
||||
|
||||
impl HintKind {
|
||||
pub fn map<T>(&self, fun: T) -> HintKind
|
||||
where
|
||||
T: FnOnce(&TypeKind) -> TypeKind,
|
||||
{
|
||||
match self {
|
||||
HintKind::Coerce(type_kind) => HintKind::Coerce(fun(type_kind)),
|
||||
_ => self.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<TypeKind>> for HintKind {
|
||||
fn from(value: Option<TypeKind>) -> Self {
|
||||
match value {
|
||||
Some(ty) => HintKind::Coerce(ty),
|
||||
None => HintKind::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeKind {
|
||||
pub(super) fn narrow_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
|
||||
if self == other {
|
||||
@ -85,55 +115,52 @@ impl TypeKind {
|
||||
}
|
||||
|
||||
match (self, other) {
|
||||
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => {
|
||||
match other {
|
||||
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Integer)),
|
||||
TypeKind::Vague(Vague::Integer) => Ok(TypeKind::Vague(Vague::Integer)),
|
||||
TypeKind::I8
|
||||
| TypeKind::I16
|
||||
| TypeKind::I32
|
||||
| TypeKind::I64
|
||||
| TypeKind::I128
|
||||
| TypeKind::U8
|
||||
| TypeKind::U16
|
||||
| TypeKind::U32
|
||||
| TypeKind::U64
|
||||
| TypeKind::U128 => Ok(other.clone()),
|
||||
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
||||
}
|
||||
}
|
||||
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => {
|
||||
match other {
|
||||
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)),
|
||||
TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)),
|
||||
TypeKind::F16
|
||||
| TypeKind::F32B
|
||||
| TypeKind::F32
|
||||
| TypeKind::F64
|
||||
| TypeKind::F80
|
||||
| TypeKind::F128
|
||||
| TypeKind::F128PPC => Ok(other.clone()),
|
||||
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
||||
}
|
||||
}
|
||||
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => {
|
||||
Ok(other.clone())
|
||||
}
|
||||
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => match other {
|
||||
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Integer)),
|
||||
TypeKind::Vague(Vague::Integer) => Ok(TypeKind::Vague(Vague::Integer)),
|
||||
TypeKind::I8
|
||||
| TypeKind::I16
|
||||
| TypeKind::I32
|
||||
| TypeKind::I64
|
||||
| TypeKind::I128
|
||||
| TypeKind::U8
|
||||
| TypeKind::U16
|
||||
| TypeKind::U32
|
||||
| TypeKind::U64
|
||||
| TypeKind::U128 => Ok(other.clone()),
|
||||
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
||||
},
|
||||
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => match other {
|
||||
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)),
|
||||
TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)),
|
||||
TypeKind::F16
|
||||
| TypeKind::F32B
|
||||
| TypeKind::F32
|
||||
| TypeKind::F64
|
||||
| TypeKind::F80
|
||||
| TypeKind::F128
|
||||
| TypeKind::F128PPC => Ok(other.clone()),
|
||||
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
||||
},
|
||||
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => Ok(other.clone()),
|
||||
(TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => {
|
||||
// Extracted to give priority for other collapse-error
|
||||
let collapsed = val1.narrow_into(val2)?;
|
||||
if mut1 == mut2 {
|
||||
Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2))
|
||||
} else {
|
||||
Err(ErrorKind::TypesDifferMutability(
|
||||
self.clone(),
|
||||
other.clone(),
|
||||
))
|
||||
Err(ErrorKind::TypesDifferMutability(self.clone(), other.clone()))
|
||||
}
|
||||
}
|
||||
(TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => {
|
||||
Ok(TypeKind::UserPtr(Box::new(val1.narrow_into(val2)?)))
|
||||
}
|
||||
(TypeKind::Array(val1, len1), TypeKind::Array(val2, len2)) => {
|
||||
if len1 != len2 {
|
||||
return Err(ErrorKind::TypesIncompatible(self.clone(), other.clone()));
|
||||
}
|
||||
Ok(TypeKind::Array(Box::new(val1.narrow_into(val2)?), *len1))
|
||||
}
|
||||
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
||||
}
|
||||
}
|
||||
@ -146,36 +173,30 @@ impl TypeKind {
|
||||
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => {
|
||||
TypeKind::Vague(VagueType::Unknown)
|
||||
}
|
||||
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => {
|
||||
match other {
|
||||
TypeKind::I8
|
||||
| TypeKind::I16
|
||||
| TypeKind::I32
|
||||
| TypeKind::I64
|
||||
| TypeKind::I128
|
||||
| TypeKind::U8
|
||||
| TypeKind::U16
|
||||
| TypeKind::U32
|
||||
| TypeKind::U64
|
||||
| TypeKind::U128 => TypeKind::Vague(VagueType::Integer),
|
||||
_ => TypeKind::Vague(VagueType::Unknown),
|
||||
}
|
||||
}
|
||||
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => {
|
||||
match other {
|
||||
TypeKind::F16
|
||||
| TypeKind::F32B
|
||||
| TypeKind::F32
|
||||
| TypeKind::F64
|
||||
| TypeKind::F80
|
||||
| TypeKind::F128
|
||||
| TypeKind::F128PPC => TypeKind::Vague(VagueType::Decimal),
|
||||
_ => TypeKind::Vague(VagueType::Unknown),
|
||||
}
|
||||
}
|
||||
(TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => {
|
||||
TypeKind::UserPtr(Box::new(val1.widen_into(val2)))
|
||||
}
|
||||
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => match other {
|
||||
TypeKind::I8
|
||||
| TypeKind::I16
|
||||
| TypeKind::I32
|
||||
| TypeKind::I64
|
||||
| TypeKind::I128
|
||||
| TypeKind::U8
|
||||
| TypeKind::U16
|
||||
| TypeKind::U32
|
||||
| TypeKind::U64
|
||||
| TypeKind::U128 => TypeKind::Vague(VagueType::Integer),
|
||||
_ => TypeKind::Vague(VagueType::Unknown),
|
||||
},
|
||||
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => match other {
|
||||
TypeKind::F16
|
||||
| TypeKind::F32B
|
||||
| TypeKind::F32
|
||||
| TypeKind::F64
|
||||
| TypeKind::F80
|
||||
| TypeKind::F128
|
||||
| TypeKind::F128PPC => TypeKind::Vague(VagueType::Decimal),
|
||||
_ => TypeKind::Vague(VagueType::Unknown),
|
||||
},
|
||||
(TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => TypeKind::UserPtr(Box::new(val1.widen_into(val2))),
|
||||
(TypeKind::CodegenPtr(val1), TypeKind::CodegenPtr(val2)) => {
|
||||
TypeKind::CodegenPtr(Box::new(val1.widen_into(val2)))
|
||||
}
|
||||
@ -245,16 +266,10 @@ impl TypeKind {
|
||||
Vague::TypeRef(_) => panic!("Hinted default!"),
|
||||
VagueType::Decimal => TypeKind::F32,
|
||||
},
|
||||
TypeKind::Array(type_kind, len) => {
|
||||
TypeKind::Array(Box::new(type_kind.or_default()?), *len)
|
||||
}
|
||||
TypeKind::Borrow(type_kind, mutable) => {
|
||||
TypeKind::Borrow(Box::new(type_kind.or_default()?), *mutable)
|
||||
}
|
||||
TypeKind::Array(type_kind, len) => TypeKind::Array(Box::new(type_kind.or_default()?), *len),
|
||||
TypeKind::Borrow(type_kind, mutable) => TypeKind::Borrow(Box::new(type_kind.or_default()?), *mutable),
|
||||
TypeKind::UserPtr(type_kind) => TypeKind::UserPtr(Box::new(type_kind.or_default()?)),
|
||||
TypeKind::CodegenPtr(type_kind) => {
|
||||
TypeKind::CodegenPtr(Box::new(type_kind.or_default()?))
|
||||
}
|
||||
TypeKind::CodegenPtr(type_kind) => TypeKind::CodegenPtr(Box::new(type_kind.or_default()?)),
|
||||
_ => self.clone(),
|
||||
})
|
||||
}
|
||||
@ -270,37 +285,29 @@ impl TypeKind {
|
||||
let resolved = self.resolve_weak(refs);
|
||||
match resolved {
|
||||
TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_ref(refs)), len),
|
||||
TypeKind::Borrow(inner, mutable) => {
|
||||
TypeKind::Borrow(Box::new(inner.resolve_ref(refs)), mutable)
|
||||
}
|
||||
TypeKind::Borrow(inner, mutable) => TypeKind::Borrow(Box::new(inner.resolve_ref(refs)), mutable),
|
||||
_ => resolved,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn assert_known(
|
||||
&self,
|
||||
refs: &TypeRefs,
|
||||
state: &TypecheckPassState,
|
||||
) -> Result<TypeKind, ErrorKind> {
|
||||
pub(super) fn assert_known(&self, refs: &TypeRefs, state: &TypecheckPassState) -> Result<TypeKind, ErrorKind> {
|
||||
self.is_known(refs, state).map(|_| self.clone())
|
||||
}
|
||||
|
||||
pub(super) fn is_known(
|
||||
&self,
|
||||
refs: &TypeRefs,
|
||||
state: &TypecheckPassState,
|
||||
) -> Result<(), ErrorKind> {
|
||||
pub(super) fn is_known(&self, refs: &TypeRefs, state: &TypecheckPassState) -> Result<(), ErrorKind> {
|
||||
match &self {
|
||||
TypeKind::Array(type_kind, _) => type_kind.as_ref().is_known(refs, state),
|
||||
TypeKind::CustomType(custom_type_key) => state
|
||||
.scope
|
||||
.types
|
||||
.get(custom_type_key)
|
||||
.map(|_| ())
|
||||
.ok_or(ErrorKind::NoSuchType(
|
||||
custom_type_key.0.clone(),
|
||||
state.module_id.unwrap(),
|
||||
)),
|
||||
TypeKind::CustomType(custom_type_key) => {
|
||||
state
|
||||
.scope
|
||||
.types
|
||||
.get(custom_type_key)
|
||||
.map(|_| ())
|
||||
.ok_or(ErrorKind::NoSuchType(
|
||||
custom_type_key.0.clone(),
|
||||
state.module_id.unwrap(),
|
||||
))
|
||||
}
|
||||
TypeKind::Borrow(type_kind, _) => type_kind.is_known(refs, state),
|
||||
TypeKind::UserPtr(type_kind) => type_kind.is_known(refs, state),
|
||||
TypeKind::CodegenPtr(type_kind) => type_kind.is_known(refs, state),
|
||||
|
@ -8,7 +8,7 @@ use VagueType as Vague;
|
||||
use super::{
|
||||
super::pass::{Pass, PassResult, ScopeVariable},
|
||||
typerefs::TypeRefs,
|
||||
ErrorKind, TypecheckPassState,
|
||||
ErrorKind, HintKind, TypecheckPassState,
|
||||
};
|
||||
|
||||
/// Struct used to implement a type-checking pass that can be performed on the
|
||||
@ -56,10 +56,7 @@ impl<'t> Pass for TypeCheck<'t> {
|
||||
}
|
||||
|
||||
if let Some(_) = defmap.insert(&typedef.name, typedef) {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::DuplicateTypeName(name.clone())),
|
||||
meta.clone(),
|
||||
);
|
||||
state.ok::<_, Infallible>(Err(ErrorKind::DuplicateTypeName(name.clone())), meta.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,10 +91,7 @@ fn check_typedefs_for_recursion<'a, 'b>(
|
||||
if let TypeKind::CustomType(CustomTypeKey(name, _)) = field_ty {
|
||||
if seen.contains(name) {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::RecursiveTypeDefinition(
|
||||
typedef.name.clone(),
|
||||
name.clone(),
|
||||
)),
|
||||
Err(ErrorKind::RecursiveTypeDefinition(typedef.name.clone(), name.clone())),
|
||||
typedef.meta,
|
||||
);
|
||||
} else {
|
||||
@ -113,11 +107,7 @@ fn check_typedefs_for_recursion<'a, 'b>(
|
||||
}
|
||||
|
||||
impl BinopDefinition {
|
||||
fn typecheck(
|
||||
&mut self,
|
||||
typerefs: &TypeRefs,
|
||||
state: &mut TypecheckPassState,
|
||||
) -> Result<TypeKind, ErrorKind> {
|
||||
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(typerefs, state),
|
||||
@ -141,29 +131,21 @@ impl BinopDefinition {
|
||||
let return_type = self.return_type.clone().assert_known(typerefs, state)?;
|
||||
|
||||
state.scope.return_type_hint = Some(self.return_type.clone());
|
||||
let inferred =
|
||||
self.fn_kind
|
||||
.typecheck(&typerefs, &mut state.inner(), Some(return_type.clone()));
|
||||
let inferred = self
|
||||
.fn_kind
|
||||
.typecheck(&typerefs, &mut state.inner(), Some(return_type.clone()));
|
||||
|
||||
match inferred {
|
||||
Ok(t) => return_type
|
||||
.narrow_into(&t.1)
|
||||
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
|
||||
Err(e) => Ok(state.or_else(
|
||||
Err(e),
|
||||
return_type,
|
||||
self.block_meta().unwrap_or(self.signature()),
|
||||
)),
|
||||
Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta().unwrap_or(self.signature()))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionDefinition {
|
||||
fn typecheck(
|
||||
&mut self,
|
||||
typerefs: &TypeRefs,
|
||||
state: &mut TypecheckPassState,
|
||||
) -> Result<TypeKind, ErrorKind> {
|
||||
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(typerefs, state),
|
||||
@ -185,9 +167,7 @@ impl FunctionDefinition {
|
||||
}
|
||||
|
||||
let return_type = self.return_type.clone().assert_known(typerefs, state)?;
|
||||
let inferred = self
|
||||
.kind
|
||||
.typecheck(typerefs, state, Some(self.return_type.clone()));
|
||||
let inferred = self.kind.typecheck(typerefs, state, Some(self.return_type.clone()));
|
||||
|
||||
match inferred {
|
||||
Ok(t) => return_type
|
||||
@ -208,14 +188,10 @@ impl FunctionDefinitionKind {
|
||||
match self {
|
||||
FunctionDefinitionKind::Local(block, _) => {
|
||||
state.scope.return_type_hint = hint.clone();
|
||||
block.typecheck(&mut state.inner(), &typerefs, hint.as_ref())
|
||||
}
|
||||
FunctionDefinitionKind::Extern(_) => {
|
||||
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
|
||||
}
|
||||
FunctionDefinitionKind::Intrinsic(..) => {
|
||||
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
|
||||
block.typecheck(&mut state.inner(), &typerefs, hint.into())
|
||||
}
|
||||
FunctionDefinitionKind::Extern(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
|
||||
FunctionDefinitionKind::Intrinsic(..) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,7 +201,7 @@ impl Block {
|
||||
&mut self,
|
||||
state: &mut TypecheckPassState,
|
||||
typerefs: &TypeRefs,
|
||||
hint_t: Option<&TypeKind>,
|
||||
hint_t: HintKind,
|
||||
) -> Result<(ReturnKind, TypeKind), ErrorKind> {
|
||||
let mut state = state.inner();
|
||||
|
||||
@ -241,9 +217,10 @@ impl Block {
|
||||
variable_reference.2,
|
||||
);
|
||||
|
||||
// Typecheck (and coerce) expression with said type
|
||||
let res = expression.typecheck(&mut state, &typerefs, Some(&var_t_resolved));
|
||||
dbg!(&var_t_resolved);
|
||||
|
||||
// Typecheck (and coerce) expression with said type
|
||||
let res = expression.typecheck(&mut state, &typerefs, HintKind::Coerce(var_t_resolved.clone()));
|
||||
// If expression resolution itself was erronous, resolve as
|
||||
// Unknown and note error.
|
||||
let res = state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1);
|
||||
@ -271,7 +248,7 @@ impl Block {
|
||||
);
|
||||
|
||||
// Re-typecheck and coerce expression to default type
|
||||
let expr_res = expression.typecheck(&mut state, &typerefs, Some(&res_t));
|
||||
let expr_res = expression.typecheck(&mut state, &typerefs, HintKind::Coerce(res_t.clone()));
|
||||
state.ok(expr_res, expression.1);
|
||||
|
||||
res_t
|
||||
@ -293,21 +270,19 @@ impl Block {
|
||||
mutable: *mutable,
|
||||
},
|
||||
)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(
|
||||
variable_reference.1.clone(),
|
||||
)));
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(variable_reference.1.clone())));
|
||||
state.ok(res, variable_reference.2);
|
||||
None
|
||||
}
|
||||
StmtKind::Set(lhs, rhs) => {
|
||||
// Typecheck expression and coerce to variable type
|
||||
let lhs_res = lhs.typecheck(&mut state, typerefs, None);
|
||||
let lhs_res = lhs.typecheck(&mut state, typerefs, HintKind::Default);
|
||||
// If expression resolution itself was erronous, resolve as
|
||||
// Unknown.
|
||||
let lhs_ty = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
||||
|
||||
// Typecheck expression and coerce to variable type
|
||||
let res = rhs.typecheck(&mut state, &typerefs, Some(&lhs_ty));
|
||||
let res = rhs.typecheck(&mut state, &typerefs, HintKind::Coerce(lhs_ty.clone()));
|
||||
|
||||
// If expression resolution itself was erronous, resolve as
|
||||
// Unknown.
|
||||
@ -342,31 +317,21 @@ impl Block {
|
||||
}
|
||||
StmtKind::Import(_) => todo!(),
|
||||
StmtKind::Expression(expression) => {
|
||||
let res = expression.typecheck(&mut state, &typerefs, None);
|
||||
let res = expression.typecheck(&mut state, &typerefs, HintKind::None);
|
||||
state.or_else(res, TypeKind::Void, expression.1);
|
||||
if let Ok((kind, _)) =
|
||||
expression.return_type(typerefs, state.module_id.unwrap())
|
||||
{
|
||||
if let Ok((kind, _)) = expression.return_type(typerefs, state.module_id.unwrap()) {
|
||||
Some((kind, expression))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
StmtKind::While(WhileStatement {
|
||||
condition,
|
||||
block,
|
||||
meta,
|
||||
}) => {
|
||||
let condition_ty =
|
||||
condition.typecheck(&mut state, typerefs, Some(&TypeKind::Bool))?;
|
||||
StmtKind::While(WhileStatement { condition, block, meta }) => {
|
||||
let condition_ty = condition.typecheck(&mut state, typerefs, HintKind::Coerce(TypeKind::Bool))?;
|
||||
if condition_ty.assert_known(typerefs, &state)? != TypeKind::Bool {
|
||||
state.note_errors(
|
||||
&vec![ErrorKind::TypesIncompatible(condition_ty, TypeKind::Bool)],
|
||||
*meta,
|
||||
);
|
||||
state.note_errors(&vec![ErrorKind::TypesIncompatible(condition_ty, TypeKind::Bool)], *meta);
|
||||
}
|
||||
|
||||
block.typecheck(&mut state, typerefs, None)?;
|
||||
block.typecheck(&mut state, typerefs, HintKind::None)?;
|
||||
|
||||
None
|
||||
}
|
||||
@ -382,7 +347,7 @@ impl Block {
|
||||
// block)
|
||||
if let Some((ReturnKind::Hard, expr)) = early_return {
|
||||
let hint = state.scope.return_type_hint.clone();
|
||||
let res = expr.typecheck(&mut state, &typerefs, hint.as_ref());
|
||||
let res = expr.typecheck(&mut state, &typerefs, hint.into());
|
||||
return Ok((
|
||||
ReturnKind::Hard,
|
||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
||||
@ -392,11 +357,11 @@ impl Block {
|
||||
if let Some((return_kind, expr)) = &mut self.return_expression {
|
||||
// Use function return type as hint if return is hard.
|
||||
let ret_hint_t = match return_kind {
|
||||
ReturnKind::Hard => state.scope.return_type_hint.clone(),
|
||||
ReturnKind::Soft => hint_t.cloned(),
|
||||
ReturnKind::Hard => state.scope.return_type_hint.clone().into(),
|
||||
ReturnKind::Soft => hint_t,
|
||||
};
|
||||
if let Some(expr) = expr {
|
||||
let res = expr.typecheck(&mut state, &typerefs, ret_hint_t.as_ref());
|
||||
let res = expr.typecheck(&mut state, &typerefs, ret_hint_t.into());
|
||||
Ok((
|
||||
*return_kind,
|
||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
||||
@ -415,7 +380,7 @@ impl Expression {
|
||||
&mut self,
|
||||
state: &mut TypecheckPassState,
|
||||
typerefs: &TypeRefs,
|
||||
hint_t: Option<&TypeKind>,
|
||||
hint_t: HintKind,
|
||||
) -> Result<TypeKind, ErrorKind> {
|
||||
match &mut self.0 {
|
||||
ExprKind::Variable(var_ref) => {
|
||||
@ -443,82 +408,41 @@ impl Expression {
|
||||
Ok(var_ref.0.clone())
|
||||
}
|
||||
ExprKind::Literal(literal) => {
|
||||
*literal = literal.clone().try_coerce(hint_t.cloned())?;
|
||||
*literal = literal.clone().try_coerce(hint_t)?;
|
||||
Ok(literal.as_type())
|
||||
}
|
||||
ExprKind::BinOp(op, lhs, rhs) => {
|
||||
ExprKind::BinOp(op, lhs, rhs, ret_ty) => {
|
||||
// First find unfiltered parameters to binop
|
||||
let lhs_res = lhs.typecheck(state, &typerefs, None);
|
||||
let lhs_res = lhs.typecheck(state, &typerefs, HintKind::None);
|
||||
let rhs_res = rhs.typecheck(state, &typerefs, HintKind::None);
|
||||
let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
||||
let rhs_res = rhs.typecheck(state, &typerefs, None);
|
||||
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
||||
|
||||
let cloned = state.scope.binops.clone();
|
||||
let mut iter = cloned.iter();
|
||||
let operator = loop {
|
||||
let Some((_, binop)) = iter.next() else {
|
||||
break None;
|
||||
};
|
||||
if binop.operator != *op {
|
||||
continue;
|
||||
}
|
||||
if let Some(hint_t) = hint_t {
|
||||
if binop.return_ty == *hint_t {
|
||||
if let Some(_) = TypeKind::binop_type(&lhs_type, &rhs_type, binop) {
|
||||
break Some(binop);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(_) = TypeKind::binop_type(&lhs_type, &rhs_type, binop) {
|
||||
break Some(binop);
|
||||
}
|
||||
let mut expected_return_ty = ret_ty.resolve_ref(typerefs);
|
||||
if let HintKind::Coerce(hint_t) = hint_t {
|
||||
expected_return_ty = state.or_else(
|
||||
expected_return_ty.narrow_into(&hint_t),
|
||||
TypeKind::Vague(VagueType::Unknown),
|
||||
self.1,
|
||||
);
|
||||
};
|
||||
|
||||
if let Some(operator) = operator {
|
||||
// Re-typecheck with found operator hints
|
||||
let (lhs_ty, rhs_ty) = TypeKind::try_collapse_two(
|
||||
(&lhs_type, &rhs_type),
|
||||
(&operator.hands.0, &operator.hands.1),
|
||||
)
|
||||
.unwrap();
|
||||
let lhs_res = lhs.typecheck(state, &typerefs, Some(&lhs_ty));
|
||||
let rhs_res = rhs.typecheck(state, &typerefs, Some(&rhs_ty));
|
||||
state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
||||
state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
||||
Ok(operator.return_ty.clone())
|
||||
let binops = state.scope.binops.filter(&pass::ScopeBinopKey {
|
||||
params: (lhs_type.clone(), rhs_type.clone()),
|
||||
operator: *op,
|
||||
});
|
||||
if let Some(binop) = binops
|
||||
.iter()
|
||||
.filter(|f| f.1.return_ty.narrow_into(&expected_return_ty).is_ok())
|
||||
.map(|v| (v.1.clone()))
|
||||
.next()
|
||||
{
|
||||
lhs.typecheck(state, &typerefs, HintKind::Coerce(binop.hands.0.clone()))?;
|
||||
rhs.typecheck(state, &typerefs, HintKind::Coerce(binop.hands.1.clone()))?;
|
||||
*ret_ty = binop.narrow(&lhs_type, &rhs_type).unwrap().2;
|
||||
Ok(ret_ty.clone())
|
||||
} else {
|
||||
// Re-typecheck with typical everyday binop
|
||||
let lhs_res = lhs.typecheck(
|
||||
state,
|
||||
&typerefs,
|
||||
hint_t.and_then(|t| t.simple_binop_hint(op)).as_ref(),
|
||||
);
|
||||
let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
||||
let rhs_res = rhs.typecheck(state, &typerefs, Some(&lhs_type));
|
||||
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
||||
|
||||
let both_t = lhs_type.narrow_into(&rhs_type)?;
|
||||
|
||||
if *op == BinaryOperator::Minus && !lhs_type.signed() {
|
||||
if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?)
|
||||
{
|
||||
if lhs_val < rhs_val {
|
||||
return Err(ErrorKind::NegativeUnsignedValue(lhs_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(collapsed) = state.ok(rhs_type.narrow_into(&rhs_type), self.1) {
|
||||
// Try to coerce both sides again with collapsed type
|
||||
lhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
||||
rhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
|
||||
}
|
||||
|
||||
both_t
|
||||
.simple_binop_type(op)
|
||||
.ok_or(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type))
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
ExprKind::FunctionCall(function_call) => {
|
||||
@ -551,21 +475,16 @@ impl Expression {
|
||||
.into_iter()
|
||||
.chain(iter::repeat(TypeKind::Vague(Vague::Unknown)));
|
||||
|
||||
for (param, true_param_t) in
|
||||
function_call.parameters.iter_mut().zip(true_params_iter)
|
||||
{
|
||||
for (param, true_param_t) in function_call.parameters.iter_mut().zip(true_params_iter) {
|
||||
// Typecheck every param separately
|
||||
let param_res = param.typecheck(state, &typerefs, Some(&true_param_t));
|
||||
let param_t =
|
||||
state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1);
|
||||
let param_res = param.typecheck(state, &typerefs, HintKind::Coerce(true_param_t.clone()));
|
||||
let param_t = state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1);
|
||||
state.ok(param_t.narrow_into(&true_param_t), param.1);
|
||||
}
|
||||
|
||||
// Make sure function return type is the same as the claimed
|
||||
// return type
|
||||
let ret_t = f
|
||||
.ret
|
||||
.narrow_into(&function_call.return_type.resolve_ref(typerefs))?;
|
||||
let ret_t = f.ret.narrow_into(&function_call.return_type.resolve_ref(typerefs))?;
|
||||
// Update typing to be more accurate
|
||||
function_call.return_type = ret_t.clone();
|
||||
Ok(ret_t.resolve_ref(typerefs))
|
||||
@ -574,18 +493,17 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
||||
let cond_res = cond.typecheck(state, &typerefs, Some(&TypeKind::Bool));
|
||||
let cond_res = cond.typecheck(state, &typerefs, HintKind::Coerce(TypeKind::Bool));
|
||||
let cond_t = state.or_else(cond_res, TypeKind::Vague(Vague::Unknown), cond.1);
|
||||
state.ok(cond_t.narrow_into(&TypeKind::Bool), cond.1);
|
||||
|
||||
// Typecheck then/else return types and make sure they are the
|
||||
// same, if else exists.
|
||||
let then_res = lhs.typecheck(state, &typerefs, hint_t);
|
||||
let then_res = lhs.typecheck(state, &typerefs, hint_t.clone());
|
||||
let then_ret_t = state.or_else(then_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
||||
let else_ret_t = if let Some(else_expr) = rhs.as_mut() {
|
||||
let res = else_expr.typecheck(state, &typerefs, hint_t);
|
||||
let else_ret_t =
|
||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), else_expr.1);
|
||||
let res = else_expr.typecheck(state, &typerefs, hint_t.clone());
|
||||
let else_ret_t = state.or_else(res, TypeKind::Vague(Vague::Unknown), else_expr.1);
|
||||
|
||||
else_ret_t
|
||||
} else {
|
||||
@ -602,8 +520,8 @@ impl Expression {
|
||||
if let Some(rhs) = rhs.as_mut() {
|
||||
// If rhs existed, typecheck both sides to perform type
|
||||
// coercion.
|
||||
let lhs_res = lhs.typecheck(state, &typerefs, Some(&collapsed));
|
||||
let rhs_res = rhs.typecheck(state, &typerefs, Some(&collapsed));
|
||||
let lhs_res = lhs.typecheck(state, &typerefs, HintKind::Coerce(collapsed.clone()));
|
||||
let rhs_res = rhs.typecheck(state, &typerefs, HintKind::Coerce(collapsed.clone()));
|
||||
state.ok(lhs_res, lhs.1);
|
||||
state.ok(rhs_res, rhs.1);
|
||||
}
|
||||
@ -618,12 +536,13 @@ impl Expression {
|
||||
ExprKind::Indexed(expression, elem_ty, idx_expr) => {
|
||||
// Try to unwrap hint type from array if possible
|
||||
let hint_t = hint_t.map(|t| match t {
|
||||
TypeKind::Array(type_kind, _) => &type_kind,
|
||||
_ => t,
|
||||
TypeKind::Array(type_kind, _) => *type_kind.clone(),
|
||||
_ => t.clone(),
|
||||
});
|
||||
|
||||
// Typecheck and narrow index-expression
|
||||
let idx_expr_res = idx_expr.typecheck(state, typerefs, Some(&TypeKind::U32));
|
||||
let idx_expr_res =
|
||||
idx_expr.typecheck(state, typerefs, HintKind::Coerce(TypeKind::Vague(VagueType::Integer)));
|
||||
state.ok(idx_expr_res, idx_expr.1);
|
||||
|
||||
// TODO it could be possible to check length against constants..
|
||||
@ -645,14 +564,14 @@ impl Expression {
|
||||
ExprKind::Array(expressions) => {
|
||||
// Try to unwrap hint type from array if possible
|
||||
let hint_t = hint_t.map(|t| match t {
|
||||
TypeKind::Array(type_kind, _) => &type_kind,
|
||||
_ => t,
|
||||
TypeKind::Array(type_kind, _) => *type_kind.clone(),
|
||||
_ => t.clone(),
|
||||
});
|
||||
|
||||
let mut expr_result = try_all(
|
||||
expressions
|
||||
.iter_mut()
|
||||
.map(|e| e.typecheck(state, typerefs, hint_t))
|
||||
.map(|e| e.typecheck(state, typerefs, hint_t.clone()))
|
||||
.collect(),
|
||||
);
|
||||
match &mut expr_result {
|
||||
@ -662,10 +581,7 @@ impl Expression {
|
||||
for other in iter {
|
||||
state.ok(first.narrow_into(other), self.1);
|
||||
}
|
||||
Ok(TypeKind::Array(
|
||||
Box::new(first.clone()),
|
||||
expressions.len() as u64,
|
||||
))
|
||||
Ok(TypeKind::Array(Box::new(first.clone()), expressions.len() as u64))
|
||||
} else {
|
||||
Ok(TypeKind::Array(Box::new(TypeKind::Void), 0))
|
||||
}
|
||||
@ -684,9 +600,8 @@ impl Expression {
|
||||
let expected_ty = type_kind.resolve_ref(typerefs);
|
||||
|
||||
// Typecheck expression
|
||||
let expr_res = expression.typecheck(state, typerefs, Some(&expected_ty));
|
||||
let expr_ty =
|
||||
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
|
||||
let expr_res = expression.typecheck(state, typerefs, HintKind::Coerce(expected_ty.clone()));
|
||||
let expr_ty = state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
|
||||
|
||||
if let TypeKind::CustomType(key) = expr_ty {
|
||||
let struct_type = state
|
||||
@ -717,27 +632,40 @@ impl Expression {
|
||||
.get_struct_type(&type_key)
|
||||
.ok_or(ErrorKind::NoSuchType(struct_name.clone(), type_key.1))?
|
||||
.clone();
|
||||
|
||||
let mut expected_fields = if let Some(struct_ty) = state.scope.get_struct_type(&type_key) {
|
||||
struct_ty.0.iter().map(|f| f.0.clone()).collect()
|
||||
} else {
|
||||
HashSet::new()
|
||||
};
|
||||
|
||||
for (field_name, field_expr) in items {
|
||||
// Get expected type, or error if field does not exist
|
||||
let expected_ty = state.or_else(
|
||||
struct_def
|
||||
.get_field_ty(field_name)
|
||||
.ok_or(ErrorKind::NoSuchField(format!(
|
||||
"{}.{}",
|
||||
struct_name, field_name
|
||||
))),
|
||||
.ok_or(ErrorKind::NoSuchField(format!("{}.{}", struct_name, field_name))),
|
||||
&TypeKind::Vague(VagueType::Unknown),
|
||||
field_expr.1,
|
||||
);
|
||||
expected_fields.remove(field_name);
|
||||
|
||||
// Typecheck the actual expression
|
||||
let expr_res = field_expr.typecheck(state, typerefs, Some(expected_ty));
|
||||
let expr_ty =
|
||||
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1);
|
||||
let expr_res = field_expr.typecheck(state, typerefs, HintKind::Coerce(expected_ty.clone()));
|
||||
let expr_ty = state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1);
|
||||
|
||||
// Make sure both are the same type, report error if not
|
||||
state.ok(expr_ty.narrow_into(&expr_ty), field_expr.1);
|
||||
}
|
||||
|
||||
state.note_errors(
|
||||
&expected_fields
|
||||
.into_iter()
|
||||
.map(|v| ErrorKind::MissingStructField(v))
|
||||
.collect(),
|
||||
self.1,
|
||||
);
|
||||
|
||||
Ok(TypeKind::CustomType(type_key))
|
||||
}
|
||||
ExprKind::Borrow(var_ref, mutable) => {
|
||||
@ -798,7 +726,7 @@ impl Expression {
|
||||
Ok(*inner)
|
||||
}
|
||||
ExprKind::CastTo(expression, type_kind) => {
|
||||
let expr = expression.typecheck(state, typerefs, Some(&type_kind))?;
|
||||
let expr = expression.typecheck(state, typerefs, HintKind::Default)?;
|
||||
expr.resolve_ref(typerefs).cast_into(type_kind)
|
||||
}
|
||||
}
|
||||
@ -808,11 +736,11 @@ impl Expression {
|
||||
impl Literal {
|
||||
/// Try to coerce this literal, ie. convert it to a more specific type in
|
||||
/// regards to the given hint if any.
|
||||
fn try_coerce(self, hint: Option<TypeKind>) -> Result<Self, ErrorKind> {
|
||||
if let Some(hint) = &hint {
|
||||
use Literal as L;
|
||||
use VagueLiteral as VagueL;
|
||||
fn try_coerce(self, hint: HintKind) -> Result<Self, ErrorKind> {
|
||||
use Literal as L;
|
||||
use VagueLiteral as VagueL;
|
||||
|
||||
if let HintKind::Coerce(hint) = &hint {
|
||||
if *hint == self.as_type() {
|
||||
return Ok(self);
|
||||
}
|
||||
@ -847,6 +775,14 @@ impl Literal {
|
||||
(_, TypeKind::Vague(_)) => self,
|
||||
_ => Err(ErrorKind::LiteralIncompatible(self, hint.clone()))?,
|
||||
})
|
||||
} else if hint == HintKind::Default {
|
||||
match self {
|
||||
Literal::Vague(vague) => match vague {
|
||||
VagueLiteral::Number(val) => Ok(L::I32(val as i32)),
|
||||
VagueLiteral::Decimal(val) => Ok(L::F32(val as f32)),
|
||||
},
|
||||
_ => Ok(self),
|
||||
}
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
|
@ -12,9 +12,8 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
mir::{
|
||||
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition,
|
||||
FunctionDefinitionKind, IfExpression, Module, ReturnKind, StmtKind, TypeKind,
|
||||
WhileStatement,
|
||||
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
|
||||
IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
|
||||
},
|
||||
util::try_all,
|
||||
};
|
||||
@ -46,10 +45,7 @@ impl<'t> Pass for TypeInference<'t> {
|
||||
for function in &mut module.functions {
|
||||
if let Some(kind) = seen_functions.get(&function.name) {
|
||||
state.note_errors(
|
||||
&vec![ErrorKind::FunctionAlreadyDefined(
|
||||
function.name.clone(),
|
||||
*kind,
|
||||
)],
|
||||
&vec![ErrorKind::FunctionAlreadyDefined(function.name.clone(), *kind)],
|
||||
function.signature(),
|
||||
);
|
||||
} else {
|
||||
@ -70,8 +66,7 @@ impl<'t> Pass for TypeInference<'t> {
|
||||
params: (binop.lhs.1.clone(), binop.rhs.1.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.1.category().is_simple_maths())
|
||||
{
|
||||
state.note_errors(
|
||||
&vec![ErrorKind::BinaryOpAlreadyDefined(
|
||||
@ -100,18 +95,10 @@ impl<'t> Pass for TypeInference<'t> {
|
||||
}
|
||||
|
||||
impl BinopDefinition {
|
||||
fn infer_types(
|
||||
&mut self,
|
||||
type_refs: &TypeRefs,
|
||||
state: &mut TypecheckPassState,
|
||||
) -> Result<(), ErrorKind> {
|
||||
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.1.assert_unvague(), Vague(Unknown), self.signature());
|
||||
state.ok(
|
||||
scope_hints
|
||||
.new_var(self.lhs.0.clone(), false, &lhs_ty)
|
||||
@ -119,11 +106,7 @@ impl BinopDefinition {
|
||||
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.1.assert_unvague(), Vague(Unknown), self.signature());
|
||||
|
||||
state.ok(
|
||||
scope_hints
|
||||
@ -132,10 +115,11 @@ impl BinopDefinition {
|
||||
self.signature(),
|
||||
);
|
||||
|
||||
let ret_ty =
|
||||
self.fn_kind
|
||||
.infer_types(state, &scope_hints, Some(self.return_type.clone()))?;
|
||||
let ret_ty = self
|
||||
.fn_kind
|
||||
.infer_types(state, &scope_hints, Some(self.return_type.clone()))?;
|
||||
if let Some(mut ret_ty) = ret_ty {
|
||||
dbg!(&ret_ty, &self.return_type);
|
||||
ret_ty.narrow(&scope_hints.from_type(&self.return_type).unwrap());
|
||||
}
|
||||
|
||||
@ -144,11 +128,7 @@ impl BinopDefinition {
|
||||
}
|
||||
|
||||
impl FunctionDefinition {
|
||||
fn infer_types(
|
||||
&mut self,
|
||||
type_refs: &TypeRefs,
|
||||
state: &mut TypecheckPassState,
|
||||
) -> Result<(), ErrorKind> {
|
||||
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());
|
||||
@ -217,12 +197,14 @@ impl Block {
|
||||
let mut state = state.inner();
|
||||
let inner_refs = outer_refs.inner();
|
||||
|
||||
// Keep track of variables created in this scope
|
||||
let mut scope_variables = Vec::new();
|
||||
|
||||
for statement in &mut self.statements {
|
||||
match &mut statement.0 {
|
||||
StmtKind::Let(var, mutable, expr) => {
|
||||
// Get the TypeRef for this variable declaration
|
||||
let mut var_ref =
|
||||
state.ok(inner_refs.new_var(var.1.clone(), *mutable, &var.0), var.2);
|
||||
let mut var_ref = state.ok(inner_refs.new_var(var.1.clone(), *mutable, &var.0), var.2);
|
||||
|
||||
// If ok, update the MIR type to this TypeRef
|
||||
if let Some(var_ref) = &var_ref {
|
||||
@ -235,11 +217,12 @@ impl Block {
|
||||
|
||||
// Try to narrow the variable type declaration with the
|
||||
// expression
|
||||
if let (Some(var_ref), Some(expr_ty_ref)) =
|
||||
(var_ref.as_mut(), expr_ty_ref.as_mut())
|
||||
{
|
||||
if let (Some(var_ref), Some(expr_ty_ref)) = (var_ref.as_mut(), expr_ty_ref.as_mut()) {
|
||||
var_ref.narrow(&expr_ty_ref);
|
||||
}
|
||||
|
||||
// Add variable to list of tracked variables
|
||||
scope_variables.push(var.clone());
|
||||
}
|
||||
StmtKind::Set(lhs, rhs) => {
|
||||
// Infer hints for the expression itself
|
||||
@ -260,9 +243,7 @@ impl Block {
|
||||
let expr_res = expr.infer_types(&mut state, &inner_refs);
|
||||
state.ok(expr_res, expr.1);
|
||||
}
|
||||
StmtKind::While(WhileStatement {
|
||||
condition, block, ..
|
||||
}) => {
|
||||
StmtKind::While(WhileStatement { condition, block, .. }) => {
|
||||
condition.infer_types(&mut state, &inner_refs)?;
|
||||
block.infer_types(&mut state, &inner_refs)?;
|
||||
}
|
||||
@ -291,6 +272,12 @@ impl Block {
|
||||
}
|
||||
}
|
||||
|
||||
// if variables aren't known at this time, they will never be. Default
|
||||
// their types.
|
||||
for variable in scope_variables {
|
||||
inner_refs.try_default_deep(&variable.0);
|
||||
}
|
||||
|
||||
Ok((kind, ret_type_ref))
|
||||
}
|
||||
}
|
||||
@ -317,42 +304,52 @@ impl Expression {
|
||||
type_ref
|
||||
}
|
||||
ExprKind::Literal(literal) => Ok(type_refs.from_type(&literal.as_type()).unwrap()),
|
||||
ExprKind::BinOp(op, lhs, rhs) => {
|
||||
ExprKind::BinOp(op, lhs, rhs, return_ty) => {
|
||||
// Infer LHS and RHS, and return binop type
|
||||
let mut lhs_ref = lhs.infer_types(state, type_refs)?;
|
||||
let mut rhs_ref = rhs.infer_types(state, type_refs)?;
|
||||
|
||||
if let Ok(binop) = type_refs
|
||||
.binop(op, &mut lhs_ref, &mut rhs_ref, &state.scope.binops)
|
||||
.ok_or(ErrorKind::TypesIncompatible(
|
||||
let binops = if let (Some(lhs_ty), Some(rhs_ty)) = (lhs_ref.resolve_deep(), rhs_ref.resolve_deep()) {
|
||||
let mut applying_binops = Vec::new();
|
||||
for (_, binop) in state.scope.binops.iter() {
|
||||
if binop.operator != *op {
|
||||
continue;
|
||||
}
|
||||
if let Some(_) = binop.narrow(&lhs_ty, &rhs_ty) {
|
||||
applying_binops.push(binop.clone());
|
||||
continue;
|
||||
}
|
||||
if binop.operator.is_commutative() {
|
||||
if let Some(_) = binop.narrow(&lhs_ty, &rhs_ty) {
|
||||
applying_binops.push(binop.clone());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
applying_binops
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
if binops.len() > 0 {
|
||||
let binop = unsafe { binops.get_unchecked(0) };
|
||||
let mut widened_lhs = binop.hands.0.clone();
|
||||
let mut widened_rhs = binop.hands.1.clone();
|
||||
for binop in binops.iter().skip(1) {
|
||||
widened_lhs = widened_lhs.widen_into(&binop.hands.0);
|
||||
widened_rhs = widened_rhs.widen_into(&binop.hands.1);
|
||||
}
|
||||
let binop_res = type_refs.from_binop(*op, &lhs_ref, &rhs_ref);
|
||||
lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap());
|
||||
rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap());
|
||||
*return_ty = binop_res.as_type();
|
||||
Ok(binop_res)
|
||||
} else {
|
||||
Err(ErrorKind::InvalidBinop(
|
||||
*op,
|
||||
lhs_ref.resolve_deep().unwrap(),
|
||||
rhs_ref.resolve_deep().unwrap(),
|
||||
))
|
||||
{
|
||||
Ok(binop)
|
||||
} else {
|
||||
let typeref = state.or_else(
|
||||
lhs_ref.narrow(&rhs_ref).ok_or(ErrorKind::InvalidBinop(
|
||||
*op,
|
||||
lhs_ref.resolve_deep().unwrap(),
|
||||
rhs_ref.resolve_deep().unwrap(),
|
||||
)),
|
||||
type_refs.from_type(&Vague(Unknown)).unwrap(),
|
||||
self.1,
|
||||
);
|
||||
Ok(type_refs
|
||||
.from_type(
|
||||
&typeref
|
||||
.resolve_deep()
|
||||
.unwrap()
|
||||
.simple_binop_type(op)
|
||||
.ok_or(ErrorKind::InvalidBinop(
|
||||
*op,
|
||||
lhs_ref.resolve_deep().unwrap(),
|
||||
rhs_ref.resolve_deep().unwrap(),
|
||||
))?,
|
||||
)
|
||||
.unwrap())
|
||||
}
|
||||
}
|
||||
ExprKind::FunctionCall(function_call) => {
|
||||
@ -369,9 +366,7 @@ impl Expression {
|
||||
// many were provided)
|
||||
let true_params_iter = fn_call.params.iter().chain(iter::repeat(&Vague(Unknown)));
|
||||
|
||||
for (param_expr, param_t) in
|
||||
function_call.parameters.iter_mut().zip(true_params_iter)
|
||||
{
|
||||
for (param_expr, param_t) in function_call.parameters.iter_mut().zip(true_params_iter) {
|
||||
let expr_res = param_expr.infer_types(state, type_refs);
|
||||
if let Some(mut param_ref) = state.ok(expr_res, param_expr.1) {
|
||||
param_ref.narrow(&mut type_refs.from_type(param_t).unwrap());
|
||||
@ -402,12 +397,10 @@ impl Expression {
|
||||
|
||||
// Narrow LHS to the same type as RHS and return it's return type
|
||||
if let (Some(mut lhs_hints), Some(mut rhs_hints)) = (lhs_hints, rhs_hints) {
|
||||
lhs_hints
|
||||
.narrow(&mut rhs_hints)
|
||||
.ok_or(ErrorKind::TypesIncompatible(
|
||||
lhs_hints.resolve_deep().unwrap(),
|
||||
rhs_hints.resolve_deep().unwrap(),
|
||||
))
|
||||
lhs_hints.narrow(&mut rhs_hints).ok_or(ErrorKind::TypesIncompatible(
|
||||
lhs_hints.resolve_deep().unwrap(),
|
||||
rhs_hints.resolve_deep().unwrap(),
|
||||
))
|
||||
} else {
|
||||
// Failed to retrieve types from either
|
||||
Ok(type_refs.from_type(&Vague(Unknown)).unwrap())
|
||||
@ -463,15 +456,10 @@ impl Expression {
|
||||
}
|
||||
|
||||
Ok(type_refs
|
||||
.from_type(&Array(
|
||||
Box::new(first.as_type()),
|
||||
expressions.len() as u64,
|
||||
))
|
||||
.from_type(&Array(Box::new(first.as_type()), expressions.len() as u64))
|
||||
.unwrap())
|
||||
} else {
|
||||
Ok(type_refs
|
||||
.from_type(&Array(Box::new(TypeKind::Void), 0))
|
||||
.unwrap())
|
||||
Ok(type_refs.from_type(&Array(Box::new(TypeKind::Void), 0)).unwrap())
|
||||
}
|
||||
}
|
||||
Err(errors) => {
|
||||
@ -515,10 +503,7 @@ impl Expression {
|
||||
let expected_struct_ty = state
|
||||
.scope
|
||||
.get_struct_type(&type_key)
|
||||
.ok_or(ErrorKind::NoSuchType(
|
||||
struct_name.clone(),
|
||||
state.module_id.unwrap(),
|
||||
))?
|
||||
.ok_or(ErrorKind::NoSuchType(struct_name.clone(), state.module_id.unwrap()))?
|
||||
.clone();
|
||||
for field in fields {
|
||||
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
||||
@ -528,17 +513,12 @@ impl Expression {
|
||||
}
|
||||
} else {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::NoSuchField(format!(
|
||||
"{}.{}",
|
||||
struct_name, field.0
|
||||
))),
|
||||
Err(ErrorKind::NoSuchField(format!("{}.{}", struct_name, field.0))),
|
||||
field.1 .1,
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(type_refs
|
||||
.from_type(&TypeKind::CustomType(type_key.clone()))
|
||||
.unwrap())
|
||||
Ok(type_refs.from_type(&TypeKind::CustomType(type_key.clone())).unwrap())
|
||||
}
|
||||
ExprKind::Borrow(var, mutable) => {
|
||||
// Find variable type
|
||||
|
@ -4,7 +4,10 @@ use std::{
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use crate::mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType};
|
||||
use crate::{
|
||||
ast::BinopDefinition,
|
||||
mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType},
|
||||
};
|
||||
|
||||
use super::{
|
||||
super::pass::{ScopeBinopDef, ScopeBinopKey, Storage},
|
||||
@ -12,10 +15,7 @@ use super::{
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TypeRef<'scope>(
|
||||
pub(super) TypeIdRef,
|
||||
pub(super) &'scope ScopeTypeRefs<'scope>,
|
||||
);
|
||||
pub struct TypeRef<'scope>(pub(super) TypeIdRef, pub(super) &'scope ScopeTypeRefs<'scope>);
|
||||
|
||||
impl<'scope> TypeRef<'scope> {
|
||||
/// Resolve current type in a weak manner, not resolving any Arrays or
|
||||
@ -64,39 +64,42 @@ pub enum TypeRefKind {
|
||||
}
|
||||
|
||||
impl TypeRefKind {
|
||||
pub fn widen(&self, types: &TypeRefs) -> Option<TypeKind> {
|
||||
pub fn widen(&self, types: &TypeRefs) -> TypeKind {
|
||||
match self {
|
||||
TypeRefKind::BinOp(op, lhs, rhs) => {
|
||||
let mut binops = types
|
||||
.binop_types
|
||||
.iter()
|
||||
.filter(|b| b.1.operator == *op)
|
||||
.map(|b| b.1.binop_ret_ty(&lhs, &rhs))
|
||||
.map(|b| {
|
||||
b.1.narrow(&lhs.resolve_ref(types), &rhs.resolve_ref(types))
|
||||
.map(|b| b.2)
|
||||
})
|
||||
.filter_map(|s| s);
|
||||
if let Some(mut ty) = binops.next() {
|
||||
while let Some(other) = binops.next() {
|
||||
ty = ty.widen_into(&other);
|
||||
}
|
||||
Some(ty)
|
||||
ty
|
||||
} else {
|
||||
None
|
||||
TypeKind::Vague(VagueType::Unknown)
|
||||
}
|
||||
}
|
||||
TypeRefKind::Direct(ty) => match ty {
|
||||
TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id),
|
||||
_ => Some(ty.clone()),
|
||||
TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id).unwrap(),
|
||||
_ => ty.clone(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct TypeRefs {
|
||||
/// Simple list of types that variables can refrence
|
||||
pub(super) hints: RefCell<Vec<TypeRefKind>>,
|
||||
/// Indirect ID-references, referring to hints-vec
|
||||
pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
|
||||
binop_types: BinopMap,
|
||||
pub(super) binop_types: BinopMap,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TypeRefs {
|
||||
@ -105,11 +108,11 @@ impl std::fmt::Display for TypeRefs {
|
||||
let idx = *typeref.borrow();
|
||||
writeln!(
|
||||
f,
|
||||
"{:<3} = {:<3} = {:?} = {}",
|
||||
"{:<3} = {:<3} = {:?} = {:?}",
|
||||
i,
|
||||
unsafe { *self.recurse_type_ref(idx).borrow() },
|
||||
self.retrieve_typeref(idx),
|
||||
self.retrieve_wide_type(idx),
|
||||
TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self)
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
@ -117,13 +120,29 @@ impl std::fmt::Display for TypeRefs {
|
||||
}
|
||||
|
||||
impl TypeRefs {
|
||||
pub fn with_binops(binops: BinopMap) -> TypeRefs {
|
||||
TypeRefs {
|
||||
hints: Default::default(),
|
||||
type_refs: Default::default(),
|
||||
binop_types: binops,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(&self, ty: &TypeKind) -> TypeIdRef {
|
||||
let idx = self.hints.borrow().len();
|
||||
let typecell = Rc::new(RefCell::new(idx));
|
||||
self.type_refs.borrow_mut().push(typecell.clone());
|
||||
self.hints.borrow_mut().push(TypeRefKind::Direct(ty.clone()));
|
||||
typecell
|
||||
}
|
||||
|
||||
pub fn binop(&self, op: BinaryOperator, lhs: &TypeRef, rhs: &TypeRef) -> TypeIdRef {
|
||||
let idx = self.hints.borrow().len();
|
||||
let typecell = Rc::new(RefCell::new(idx));
|
||||
self.type_refs.borrow_mut().push(typecell.clone());
|
||||
self.hints
|
||||
.borrow_mut()
|
||||
.push(TypeRefKind::Direct(ty.clone()));
|
||||
.push(TypeRefKind::BinOp(op, lhs.as_type(), rhs.as_type()));
|
||||
typecell
|
||||
}
|
||||
|
||||
@ -160,14 +179,13 @@ impl TypeRefs {
|
||||
return refs.get_unchecked(idx).clone();
|
||||
}
|
||||
|
||||
pub fn retrieve_wide_type(&self, idx: usize) -> Option<TypeKind> {
|
||||
pub fn retrieve_typeref(&self, idx: usize) -> Option<TypeRefKind> {
|
||||
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
|
||||
self.hints
|
||||
.borrow()
|
||||
.get(inner_idx)
|
||||
.cloned()
|
||||
.map(|t| t.widen(self))
|
||||
.flatten()
|
||||
self.hints.borrow().get(inner_idx).cloned()
|
||||
}
|
||||
|
||||
pub fn retrieve_wide_type(&self, idx: usize) -> Option<TypeKind> {
|
||||
self.retrieve_typeref(idx).map(|t| t.widen(self))
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,9 +216,7 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
||||
return Err(ErrorKind::VariableAlreadyDefined(name));
|
||||
}
|
||||
let type_ref = self.from_type(&initial_ty).unwrap();
|
||||
self.variables
|
||||
.borrow_mut()
|
||||
.insert(name, (mutable, type_ref.0.clone()));
|
||||
self.variables.borrow_mut().insert(name, (mutable, type_ref.0.clone()));
|
||||
Ok(type_ref)
|
||||
}
|
||||
|
||||
@ -213,8 +229,7 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
||||
TypeKind::Vague(_) => self.types.new(ty),
|
||||
TypeKind::Array(elem_ty, length) => {
|
||||
let elem_ty = self.from_type(elem_ty)?;
|
||||
self.types
|
||||
.new(&TypeKind::Array(Box::new(elem_ty.as_type()), *length))
|
||||
self.types.new(&TypeKind::Array(Box::new(elem_ty.as_type()), *length))
|
||||
}
|
||||
TypeKind::Borrow(ty, mutable) => {
|
||||
let inner_ty = self.from_type(ty)?;
|
||||
@ -232,27 +247,53 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
||||
Some(TypeRef(idx, self))
|
||||
}
|
||||
|
||||
pub fn from_binop(&'outer self, op: BinaryOperator, lhs: &TypeRef, rhs: &TypeRef) -> TypeRef<'outer> {
|
||||
TypeRef(self.types.binop(op, lhs, rhs), self)
|
||||
}
|
||||
|
||||
fn narrow_to_type(&'outer self, hint: &TypeRef, ty: &TypeKind) -> Option<TypeRef<'outer>> {
|
||||
unsafe {
|
||||
let mut hints = self.types.hints.borrow_mut();
|
||||
let existing = hints.get_unchecked_mut(*hint.0.borrow());
|
||||
|
||||
match existing {
|
||||
TypeRefKind::Direct(type_kind) => {
|
||||
*type_kind = type_kind.narrow_into(&ty).ok()?;
|
||||
}
|
||||
TypeRefKind::BinOp(op, lhs, rhs) => {
|
||||
let op = op.clone();
|
||||
let lhs = lhs.clone();
|
||||
let rhs = rhs.clone();
|
||||
drop(hints);
|
||||
|
||||
let lhs_resolved = lhs.resolve_ref(self.types);
|
||||
let rhs_resolved = rhs.resolve_ref(self.types);
|
||||
|
||||
let binops = self
|
||||
.types
|
||||
.binop_types
|
||||
.iter()
|
||||
.filter(|b| b.1.operator == *op && b.1.return_ty == *ty);
|
||||
.filter(|b| b.1.operator == op && b.1.return_ty == *ty)
|
||||
.collect::<Vec<_>>();
|
||||
for binop in binops {
|
||||
if let (Ok(lhs_narrow), Ok(rhs_narrow)) = (
|
||||
lhs.narrow_into(&binop.1.hands.0),
|
||||
rhs.narrow_into(&binop.1.hands.1),
|
||||
lhs_resolved.narrow_into(&binop.1.hands.0),
|
||||
rhs_resolved.narrow_into(&binop.1.hands.1),
|
||||
) {
|
||||
*lhs = lhs_narrow;
|
||||
*rhs = rhs_narrow
|
||||
match &lhs {
|
||||
TypeKind::Vague(VagueType::TypeRef(idx)) => {
|
||||
let mut lhs_ref = TypeRef(Rc::new(RefCell::new(*idx)), self);
|
||||
self.narrow_to_type(&mut lhs_ref, &lhs_narrow).unwrap_or(lhs_ref);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
match &rhs {
|
||||
TypeKind::Vague(VagueType::TypeRef(idx)) => {
|
||||
let mut rhs_ref = TypeRef(Rc::new(RefCell::new(*idx)), self);
|
||||
self.narrow_to_type(&mut rhs_ref, &rhs_narrow).unwrap_or(rhs_ref);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -261,6 +302,27 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_default_deep(&self, ty: &TypeKind) -> Option<TypeKind> {
|
||||
Some(match &ty {
|
||||
TypeKind::Array(type_kind, _) => self.try_default_deep(type_kind)?,
|
||||
TypeKind::CustomType(_) => ty.clone(),
|
||||
TypeKind::Borrow(type_kind, _) => self.try_default_deep(type_kind)?,
|
||||
TypeKind::UserPtr(type_kind) => self.try_default_deep(type_kind)?,
|
||||
TypeKind::CodegenPtr(type_kind) => self.try_default_deep(type_kind)?,
|
||||
TypeKind::Vague(vague_type) => match vague_type {
|
||||
VagueType::Unknown => ty.clone(),
|
||||
VagueType::Integer => ty.or_default().unwrap(),
|
||||
VagueType::Decimal => ty.or_default().unwrap(),
|
||||
VagueType::TypeRef(idx) => {
|
||||
let typeref = TypeRef(Rc::new(RefCell::new(*idx)), self);
|
||||
self.narrow_to_type(&typeref, &self.try_default_deep(&typeref.resolve_deep()?)?)?
|
||||
.resolve_deep()?
|
||||
}
|
||||
},
|
||||
_ => ty.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn combine_vars(&'outer self, hint1: &TypeRef, hint2: &TypeRef) -> Option<TypeRef<'outer>> {
|
||||
unsafe {
|
||||
let ty = self
|
||||
@ -269,12 +331,22 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
||||
.borrow()
|
||||
.get_unchecked(*hint2.0.borrow())
|
||||
.clone()
|
||||
.widen(self.types)
|
||||
.unwrap();
|
||||
.widen(self.types);
|
||||
self.narrow_to_type(&hint1, &ty)?;
|
||||
let hint1_typeref = self.types.retrieve_typeref(*hint1.0.borrow()).unwrap();
|
||||
for idx in self.types.type_refs.borrow_mut().iter_mut() {
|
||||
if *idx == hint2.0 && idx != &hint1.0 {
|
||||
*idx.borrow_mut() = *hint1.0.borrow();
|
||||
match hint1_typeref {
|
||||
TypeRefKind::Direct(_) => {
|
||||
if *idx == hint2.0 && idx != &hint1.0 {
|
||||
*idx.borrow_mut() = *hint1.0.borrow();
|
||||
}
|
||||
}
|
||||
TypeRefKind::BinOp(_, _, _) => {
|
||||
// TODO may not be good ?
|
||||
// if *idx == hint2.0 && idx != &hint1.0 {
|
||||
// *idx.borrow_mut() = *hint1.0.borrow();
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(TypeRef(hint1.0.clone(), self))
|
||||
@ -297,47 +369,36 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
||||
.or(self.outer.map(|o| o.find_var(name)).flatten())
|
||||
}
|
||||
|
||||
pub fn binop(
|
||||
pub fn available_binops(
|
||||
&'outer self,
|
||||
op: &BinaryOperator,
|
||||
lhs: &mut TypeRef<'outer>,
|
||||
rhs: &mut TypeRef<'outer>,
|
||||
binops: &Storage<ScopeBinopKey, ScopeBinopDef>,
|
||||
) -> Option<TypeRef<'outer>> {
|
||||
if lhs.resolve_deep().unwrap().known().is_err()
|
||||
&& rhs.resolve_deep().unwrap().known().is_err()
|
||||
{
|
||||
return self.from_type(&TypeKind::Vague(VagueType::Unknown));
|
||||
}
|
||||
|
||||
let mut iter = binops.iter();
|
||||
loop {
|
||||
let Some((_, binop)) = iter.next() else {
|
||||
break None;
|
||||
};
|
||||
) -> Vec<ScopeBinopDef> {
|
||||
let mut applying_binops = Vec::new();
|
||||
for (_, binop) in self.types.binop_types.iter() {
|
||||
if binop.operator != *op {
|
||||
continue;
|
||||
}
|
||||
if let Some(ret) = try_binop(lhs, rhs, binop) {
|
||||
break Some(ret);
|
||||
if let Some(_) = check_binop(lhs, rhs, binop) {
|
||||
applying_binops.push(binop.clone());
|
||||
continue;
|
||||
}
|
||||
if binop.operator.is_commutative() {
|
||||
if let Some(ret) = try_binop(rhs, lhs, binop) {
|
||||
return Some(ret);
|
||||
if let Some(_) = check_binop(lhs, rhs, binop) {
|
||||
applying_binops.push(binop.clone());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
applying_binops
|
||||
}
|
||||
}
|
||||
|
||||
fn try_binop<'o>(
|
||||
fn check_binop<'o>(
|
||||
lhs: &mut TypeRef<'o>,
|
||||
rhs: &mut TypeRef<'o>,
|
||||
binop: &ScopeBinopDef,
|
||||
) -> Option<TypeRef<'o>> {
|
||||
let (lhs_ty, rhs_ty, ret_ty) =
|
||||
TypeKind::binop_type(&lhs.resolve_deep()?, &rhs.resolve_deep()?, binop)?;
|
||||
lhs.narrow(&lhs.1.from_type(&lhs_ty).unwrap()).unwrap();
|
||||
rhs.narrow(&rhs.1.from_type(&rhs_ty).unwrap()).unwrap();
|
||||
lhs.1.from_type(&ret_ty)
|
||||
) -> Option<(TypeKind, TypeKind, TypeKind)> {
|
||||
binop.narrow(&lhs.resolve_deep()?, &rhs.resolve_deep()?)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user