Compare commits
No commits in common. "5991a75d327c83577fab9a37d869f290f61ea277" and "12e2851a8bfd3c2ce959a14db11ed255e393d1a1" have entirely different histories.
5991a75d32
...
12e2851a8b
@ -49,8 +49,8 @@ Currently missing big features (TODOs) are:
|
|||||||
- ~~Debug Information~~ (DONE)
|
- ~~Debug Information~~ (DONE)
|
||||||
- ~~Fix struct initialization (wrong order and missing fields allowed now)~~
|
- ~~Fix struct initialization (wrong order and missing fields allowed now)~~
|
||||||
- ~~Not-Unary~~
|
- ~~Not-Unary~~
|
||||||
- ~~Importing types from other modules~~
|
- Importing types from other modules
|
||||||
- ~~Importable binops?~~
|
- Importable binops?
|
||||||
- Associated functions (for e.g. sizeof)
|
- Associated functions (for e.g. sizeof)
|
||||||
|
|
||||||
Big features that I want later but are not necessary:
|
Big features that I want later but are not necessary:
|
||||||
|
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;
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
import std::print;
|
|
||||||
import std::from_str;
|
|
||||||
import std::String;
|
|
||||||
|
|
||||||
fn main() -> u8 {
|
|
||||||
print(from_str("hello") + " beep: " + 1234u64);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
struct Otus {}
|
|
||||||
|
|
||||||
impl binop (lhs: Otus) + (rhs: u64) -> Otus {
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make_otus() -> Otus {
|
|
||||||
return Otus {};
|
|
||||||
}
|
|
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);
|
||||||
|
}
|
@ -5,7 +5,9 @@
|
|||||||
use std::{fmt::Debug, marker::PhantomData};
|
use std::{fmt::Debug, marker::PhantomData};
|
||||||
|
|
||||||
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue};
|
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue};
|
||||||
use debug_information::{DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue, DebugProgramValue};
|
use debug_information::{
|
||||||
|
DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue, DebugProgramValue,
|
||||||
|
};
|
||||||
use fmt::PrintableModule;
|
use fmt::PrintableModule;
|
||||||
|
|
||||||
pub mod builder;
|
pub mod builder;
|
||||||
@ -64,7 +66,13 @@ pub struct Module<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> Module<'ctx> {
|
impl<'ctx> Module<'ctx> {
|
||||||
pub fn function(&self, name: &str, ret: Type, params: Vec<Type>, flags: FunctionFlags) -> Function<'ctx> {
|
pub fn function(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
ret: Type,
|
||||||
|
params: Vec<Type>,
|
||||||
|
flags: FunctionFlags,
|
||||||
|
) -> Function<'ctx> {
|
||||||
unsafe {
|
unsafe {
|
||||||
Function {
|
Function {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -103,7 +111,10 @@ impl<'ctx> Module<'ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_debug_info(&mut self, file: DebugFileData) -> (DebugInformation, DebugProgramValue) {
|
pub fn create_debug_info(
|
||||||
|
&mut self,
|
||||||
|
file: DebugFileData,
|
||||||
|
) -> (DebugInformation, DebugProgramValue) {
|
||||||
let (debug_info, program_value) = DebugInformation::from_file(file);
|
let (debug_info, program_value) = DebugInformation::from_file(file);
|
||||||
self.debug_info = Some(debug_info.clone());
|
self.debug_info = Some(debug_info.clone());
|
||||||
(debug_info, program_value)
|
(debug_info, program_value)
|
||||||
@ -133,17 +144,10 @@ pub struct FunctionData {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash)]
|
#[derive(Debug, Clone, Copy, Hash)]
|
||||||
pub struct FunctionFlags {
|
pub struct FunctionFlags {
|
||||||
/// True in the destination module of the import, false in the source module.
|
|
||||||
pub is_extern: bool,
|
pub is_extern: bool,
|
||||||
/// Whether this function is the main function of the module, that should be
|
|
||||||
/// executed (and linked externally also).
|
|
||||||
pub is_main: bool,
|
pub is_main: bool,
|
||||||
/// Whether this function should be available externally always.
|
|
||||||
pub is_pub: bool,
|
pub is_pub: bool,
|
||||||
/// If this function is an imported function (either in the source or
|
|
||||||
/// destination module)
|
|
||||||
pub is_imported: bool,
|
pub is_imported: bool,
|
||||||
/// Whether this function should add "alwaysinline"-attribute.
|
|
||||||
pub inline: bool,
|
pub inline: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +260,11 @@ impl Instr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'builder> Block<'builder> {
|
impl<'builder> Block<'builder> {
|
||||||
pub fn build_named<T: Into<String>>(&mut self, name: T, instruction: Instr) -> CompileResult<InstructionValue> {
|
pub fn build_named<T: Into<String>>(
|
||||||
|
&mut self,
|
||||||
|
name: T,
|
||||||
|
instruction: Instr,
|
||||||
|
) -> CompileResult<InstructionValue> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.builder.add_instruction(
|
self.builder.add_instruction(
|
||||||
&self.value,
|
&self.value,
|
||||||
@ -287,13 +295,15 @@ impl<'builder> Block<'builder> {
|
|||||||
|
|
||||||
pub fn set_instr_location(&self, instruction: InstructionValue, location: DebugLocationValue) {
|
pub fn set_instr_location(&self, instruction: InstructionValue, location: DebugLocationValue) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.builder.add_instruction_location(&instruction, location);
|
self.builder
|
||||||
|
.add_instruction_location(&instruction, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_instr_metadata(&self, instruction: InstructionValue, location: DebugMetadataValue) {
|
pub fn set_instr_metadata(&self, instruction: InstructionValue, location: DebugMetadataValue) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.builder.add_instruction_metadata(&instruction, location);
|
self.builder
|
||||||
|
.add_instruction_metadata(&instruction, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,10 +610,16 @@ impl Type {
|
|||||||
| Type::U32
|
| Type::U32
|
||||||
| Type::U64
|
| Type::U64
|
||||||
| Type::U128 => TypeCategory::Integer,
|
| Type::U128 => TypeCategory::Integer,
|
||||||
Type::F16 | Type::F32B | Type::F32 | Type::F64 | Type::F80 | Type::F128 | Type::F128PPC => {
|
Type::F16
|
||||||
TypeCategory::Real
|
| Type::F32B
|
||||||
|
| Type::F32
|
||||||
|
| Type::F64
|
||||||
|
| Type::F80
|
||||||
|
| Type::F128
|
||||||
|
| Type::F128PPC => TypeCategory::Real,
|
||||||
|
Type::Bool | Type::Void | Type::CustomType(_) | Type::Array(_, _) | Type::Ptr(_) => {
|
||||||
|
TypeCategory::Other
|
||||||
}
|
}
|
||||||
Type::Bool | Type::Void | Type::CustomType(_) | Type::Array(_, _) | Type::Ptr(_) => TypeCategory::Other,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,15 +630,23 @@ impl Type {
|
|||||||
(I16, I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())),
|
(I16, I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())),
|
||||||
(I32, I64 | I128) => Some(Instr::SExt(value, other.clone())),
|
(I32, I64 | I128) => Some(Instr::SExt(value, other.clone())),
|
||||||
(I64, I128) => Some(Instr::SExt(value, other.clone())),
|
(I64, I128) => Some(Instr::SExt(value, other.clone())),
|
||||||
(I128 | U128, I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
(I128 | U128, I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => {
|
||||||
(I64 | U64, I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
Some(Instr::Trunc(value, other.clone()))
|
||||||
|
}
|
||||||
|
(I64 | U64, I32 | U32 | I16 | U16 | I8 | U8) => {
|
||||||
|
Some(Instr::Trunc(value, other.clone()))
|
||||||
|
}
|
||||||
(I32 | U32, I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
(I32 | U32, I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
||||||
(I16 | U16, I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
(I16 | U16, I8 | U8) => Some(Instr::Trunc(value, other.clone())),
|
||||||
(U8 | I8, U8 | I8 | U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => {
|
(U8 | I8, U8 | I8 | U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => {
|
||||||
Some(Instr::ZExt(value, other.clone()))
|
Some(Instr::ZExt(value, other.clone()))
|
||||||
}
|
}
|
||||||
(U16 | I16, U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
(U16 | I16, U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => {
|
||||||
(U32 | I32, U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
Some(Instr::ZExt(value, other.clone()))
|
||||||
|
}
|
||||||
|
(U32 | I32, U32 | I32 | U64 | I64 | U128 | I128) => {
|
||||||
|
Some(Instr::ZExt(value, other.clone()))
|
||||||
|
}
|
||||||
(U64 | I64, U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
(U64 | I64, U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
||||||
(U128 | I128, U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
(U128 | I128, U128 | I128) => Some(Instr::ZExt(value, other.clone())),
|
||||||
(U8 | U16 | U32 | U64 | U128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => {
|
(U8 | U16 | U32 | U64 | U128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => {
|
||||||
@ -643,11 +667,15 @@ impl Type {
|
|||||||
(Ptr(_), I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => {
|
(Ptr(_), I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => {
|
||||||
Some(Instr::PtrToInt(value, other.clone()))
|
Some(Instr::PtrToInt(value, other.clone()))
|
||||||
}
|
}
|
||||||
(F16, F32 | F32B | F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
(F16, F32 | F32B | F64 | F80 | F128 | F128PPC) => {
|
||||||
|
Some(Instr::FPExt(value, other.clone()))
|
||||||
|
}
|
||||||
(F32 | F32B, F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
(F32 | F32B, F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
||||||
(F64, F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
(F64, F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
||||||
(F80, F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
(F80, F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
|
||||||
(F128PPC | F128, F80 | F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
|
(F128PPC | F128, F80 | F64 | F32B | F32 | F16) => {
|
||||||
|
Some(Instr::FPTrunc(value, other.clone()))
|
||||||
|
}
|
||||||
(F80, F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
|
(F80, F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
|
||||||
(F64, F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
|
(F64, F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
|
||||||
(F32B | F32, F16) => Some(Instr::FPTrunc(value, other.clone())),
|
(F32B | F32, F16) => Some(Instr::FPTrunc(value, other.clone())),
|
||||||
|
@ -4,27 +4,6 @@ extern fn malloc(size: u64) -> *u8;
|
|||||||
extern fn free(ptr: *u8);
|
extern fn free(ptr: *u8);
|
||||||
extern fn div(numerator: i32, denominator: i32) -> div_t;
|
extern fn div(numerator: i32, denominator: i32) -> div_t;
|
||||||
|
|
||||||
struct String {
|
|
||||||
inner: *char,
|
|
||||||
length: u64,
|
|
||||||
max_length: u64,
|
|
||||||
must_be_freed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl binop (lhs: String) + (rhs: *char) -> String {
|
|
||||||
let mut new = lhs;
|
|
||||||
let added = from_str(rhs);
|
|
||||||
concat_strings(&mut new, added);
|
|
||||||
free_string(&added);
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl binop (lhs: String) + (rhs: u64) -> String {
|
|
||||||
let mut new = lhs;
|
|
||||||
add_num_to_str(&mut new, rhs);
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct div_t {
|
struct div_t {
|
||||||
quotient: i32,
|
quotient: i32,
|
||||||
remainder: i32,
|
remainder: i32,
|
||||||
@ -42,6 +21,13 @@ pub fn allocate(size: u64) -> *u8 {
|
|||||||
malloc(size)
|
malloc(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct String {
|
||||||
|
inner: *char,
|
||||||
|
length: u64,
|
||||||
|
max_length: u64,
|
||||||
|
must_be_freed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_string() -> String {
|
pub fn new_string() -> String {
|
||||||
String {
|
String {
|
||||||
inner: allocate(0),
|
inner: allocate(0),
|
||||||
|
@ -95,7 +95,6 @@ impl ast::Module {
|
|||||||
},
|
},
|
||||||
meta: (*range).as_meta(module_id),
|
meta: (*range).as_meta(module_id),
|
||||||
source_module: module_id,
|
source_module: module_id,
|
||||||
importer: None,
|
|
||||||
};
|
};
|
||||||
typedefs.push(def);
|
typedefs.push(def);
|
||||||
}
|
}
|
||||||
@ -117,7 +116,6 @@ impl ast::Module {
|
|||||||
block.2.as_meta(module_id),
|
block.2.as_meta(module_id),
|
||||||
),
|
),
|
||||||
meta: signature_range.as_meta(module_id),
|
meta: signature_range.as_meta(module_id),
|
||||||
exported: false,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,6 @@ where
|
|||||||
return_type: ty.clone(),
|
return_type: ty.clone(),
|
||||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
|
||||||
meta: Default::default(),
|
meta: Default::default(),
|
||||||
exported: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +63,6 @@ where
|
|||||||
return_type: TypeKind::Bool,
|
return_type: TypeKind::Bool,
|
||||||
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))),
|
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))),
|
||||||
meta: Default::default(),
|
meta: Default::default(),
|
||||||
exported: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use scope::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mir::{
|
mir::{
|
||||||
self, implement::TypeCategory, pass::BinopKey, CustomTypeKey, FunctionDefinitionKind, NamedVariableRef,
|
self, implement::TypeCategory, pass::ScopeBinopKey, CustomTypeKey, FunctionDefinitionKind, NamedVariableRef,
|
||||||
SourceModuleId, StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
|
SourceModuleId, StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
|
||||||
},
|
},
|
||||||
util::try_all,
|
util::try_all,
|
||||||
@ -214,12 +214,8 @@ impl mir::Module {
|
|||||||
|
|
||||||
let mut binops = HashMap::new();
|
let mut binops = HashMap::new();
|
||||||
for binop in &self.binop_defs {
|
for binop in &self.binop_defs {
|
||||||
let binop_fn_name = format!(
|
|
||||||
"binop.{}.{:?}.{}.{}",
|
|
||||||
binop.lhs.1, binop.op, binop.rhs.1, binop.return_type
|
|
||||||
);
|
|
||||||
binops.insert(
|
binops.insert(
|
||||||
BinopKey {
|
ScopeBinopKey {
|
||||||
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||||
operator: binop.op,
|
operator: binop.op,
|
||||||
},
|
},
|
||||||
@ -228,14 +224,16 @@ impl mir::Module {
|
|||||||
return_ty: binop.return_type.clone(),
|
return_ty: binop.return_type.clone(),
|
||||||
kind: match &binop.fn_kind {
|
kind: match &binop.fn_kind {
|
||||||
FunctionDefinitionKind::Local(block, metadata) => {
|
FunctionDefinitionKind::Local(block, metadata) => {
|
||||||
|
let binop_fn_name = format!(
|
||||||
|
"binop.{}.{:?}.{}.{}",
|
||||||
|
binop.lhs.1, binop.op, binop.rhs.1, binop.return_type
|
||||||
|
);
|
||||||
let ir_function = module.function(
|
let ir_function = module.function(
|
||||||
&binop_fn_name,
|
&binop_fn_name,
|
||||||
binop.return_type.get_type(&type_values),
|
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 {
|
FunctionFlags {
|
||||||
inline: true,
|
inline: true,
|
||||||
is_pub: binop.exported,
|
|
||||||
is_imported: binop.exported,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -291,18 +289,7 @@ impl mir::Module {
|
|||||||
|
|
||||||
StackBinopFunctionKind::UserGenerated(ir_function)
|
StackBinopFunctionKind::UserGenerated(ir_function)
|
||||||
}
|
}
|
||||||
FunctionDefinitionKind::Extern(imported) => {
|
FunctionDefinitionKind::Extern(_) => todo!(),
|
||||||
StackBinopFunctionKind::UserGenerated(module.function(
|
|
||||||
&binop_fn_name,
|
|
||||||
binop.return_type.get_type(&type_values),
|
|
||||||
vec![binop.lhs.1.get_type(&type_values), binop.rhs.1.get_type(&type_values)],
|
|
||||||
FunctionFlags {
|
|
||||||
is_extern: true,
|
|
||||||
is_imported: *imported,
|
|
||||||
..FunctionFlags::default()
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
FunctionDefinitionKind::Intrinsic(intrinsic_function) => {
|
FunctionDefinitionKind::Intrinsic(intrinsic_function) => {
|
||||||
StackBinopFunctionKind::Intrinsic(intrinsic_function)
|
StackBinopFunctionKind::Intrinsic(intrinsic_function)
|
||||||
}
|
}
|
||||||
@ -717,7 +704,7 @@ impl mir::Expression {
|
|||||||
let lhs = lhs_val.instr();
|
let lhs = lhs_val.instr();
|
||||||
let rhs = rhs_val.instr();
|
let rhs = rhs_val.instr();
|
||||||
|
|
||||||
let operation = scope.binops.get(&BinopKey {
|
let operation = scope.binops.get(&ScopeBinopKey {
|
||||||
params: (lhs_val.1.clone(), rhs_val.1.clone()),
|
params: (lhs_val.1.clone(), rhs_val.1.clone()),
|
||||||
operator: *binop,
|
operator: *binop,
|
||||||
});
|
});
|
||||||
|
@ -8,7 +8,7 @@ use reid_lib::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
lexer::FullToken,
|
lexer::FullToken,
|
||||||
mir::{pass::BinopKey, CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind},
|
mir::{pass::ScopeBinopKey, CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{allocator::Allocator, ErrorKind, IntrinsicFunction, ModuleCodegen};
|
use super::{allocator::Allocator, ErrorKind, IntrinsicFunction, ModuleCodegen};
|
||||||
@ -24,7 +24,7 @@ pub struct Scope<'ctx, 'scope> {
|
|||||||
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>,
|
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>,
|
||||||
pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
|
pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
|
||||||
pub(super) functions: &'scope HashMap<String, Function<'ctx>>,
|
pub(super) functions: &'scope HashMap<String, Function<'ctx>>,
|
||||||
pub(super) binops: &'scope HashMap<BinopKey, StackBinopDefinition<'ctx>>,
|
pub(super) binops: &'scope HashMap<ScopeBinopKey, StackBinopDefinition<'ctx>>,
|
||||||
pub(super) stack_values: HashMap<String, StackValue>,
|
pub(super) stack_values: HashMap<String, StackValue>,
|
||||||
pub(super) debug: Option<Debug<'ctx>>,
|
pub(super) debug: Option<Debug<'ctx>>,
|
||||||
pub(super) allocator: Rc<RefCell<Allocator>>,
|
pub(super) allocator: Rc<RefCell<Allocator>>,
|
||||||
@ -150,9 +150,15 @@ impl<'ctx> StackBinopDefinition<'ctx> {
|
|||||||
StackBinopFunctionKind::UserGenerated(ir) => {
|
StackBinopFunctionKind::UserGenerated(ir) => {
|
||||||
let instr = scope
|
let instr = scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::FunctionCall(ir.value(), vec![lhs.instr(), rhs.instr()]))
|
.build(Instr::FunctionCall(
|
||||||
|
ir.value(),
|
||||||
|
vec![lhs.instr(), rhs.instr()],
|
||||||
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(StackValue(StackValueKind::Immutable(instr), self.return_ty.clone()))
|
Ok(StackValue(
|
||||||
|
StackValueKind::Immutable(instr),
|
||||||
|
self.return_ty.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]),
|
StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]),
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ pub fn perform_all_passes<'map>(
|
|||||||
for intrinsic in form_intrinsic_binops() {
|
for intrinsic in form_intrinsic_binops() {
|
||||||
binops
|
binops
|
||||||
.set(
|
.set(
|
||||||
mir::pass::BinopKey {
|
mir::pass::ScopeBinopKey {
|
||||||
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||||
operator: intrinsic.op,
|
operator: intrinsic.op,
|
||||||
},
|
},
|
||||||
@ -173,9 +173,9 @@ pub fn perform_all_passes<'map>(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut refs = TypeRefs::with_binops(binops);
|
let refs = TypeRefs::with_binops(binops);
|
||||||
|
|
||||||
let state = context.pass(&mut TypeInference { refs: &mut refs })?;
|
let state = context.pass(&mut TypeInference { refs: &refs })?;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("{:-^100}", "TYPE INFERRER OUTPUT");
|
println!("{:-^100}", "TYPE INFERRER OUTPUT");
|
||||||
|
@ -66,14 +66,8 @@ impl Display for BinopDefinition {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}impl binop ({}: {:#}) {} ({}: {:#}) -> {:#} ",
|
"impl binop ({}: {:#}) {} ({}: {:#}) -> {:#} ",
|
||||||
if self.exported { "exported " } else { "" },
|
self.lhs.0, self.lhs.1, self.op, self.rhs.0, self.rhs.1, self.return_type
|
||||||
self.lhs.0,
|
|
||||||
self.lhs.1,
|
|
||||||
self.op,
|
|
||||||
self.rhs.0,
|
|
||||||
self.rhs.1,
|
|
||||||
self.return_type
|
|
||||||
)?;
|
)?;
|
||||||
Display::fmt(&self.fn_kind, f)
|
Display::fmt(&self.fn_kind, f)
|
||||||
}
|
}
|
||||||
@ -81,17 +75,7 @@ impl Display for BinopDefinition {
|
|||||||
|
|
||||||
impl Display for TypeDefinition {
|
impl Display for TypeDefinition {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(f, "type {} = ", self.name)?;
|
||||||
f,
|
|
||||||
"type {} (mod {}{}) = ",
|
|
||||||
self.name,
|
|
||||||
self.source_module,
|
|
||||||
if let Some(mod_id) = self.importer {
|
|
||||||
format!("; imported to {}", mod_id)
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
)?;
|
|
||||||
Display::fmt(&self.kind, f)
|
Display::fmt(&self.kind, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,9 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::scope,
|
|
||||||
compile_module,
|
compile_module,
|
||||||
error_raporting::{ErrorModules, ReidError},
|
error_raporting::{ErrorModules, ReidError},
|
||||||
mir::{
|
mir::{CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind},
|
||||||
pass::BinopKey, BinopDefinition, CustomTypeKey, FunctionDefinitionKind, SourceModuleId, TypeDefinition,
|
|
||||||
TypeKind,
|
|
||||||
},
|
|
||||||
parse_module,
|
parse_module,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,8 +31,8 @@ pub enum ErrorKind {
|
|||||||
ModuleNotFound(String),
|
ModuleNotFound(String),
|
||||||
#[error("Error while compiling module {0}: {1}")]
|
#[error("Error while compiling module {0}: {1}")]
|
||||||
ModuleCompilationError(String, String),
|
ModuleCompilationError(String, String),
|
||||||
#[error("No such value {0} found in module {1}")]
|
#[error("No such function {0} found in module {1}")]
|
||||||
ImportDoesNotExist(String, String),
|
NoSuchFunctionInModule(String, String),
|
||||||
#[error("Importing function {0}::{1} not possible: {2}")]
|
#[error("Importing function {0}::{1} not possible: {2}")]
|
||||||
FunctionImportIssue(String, String, EqualsIssue),
|
FunctionImportIssue(String, String, EqualsIssue),
|
||||||
#[error("Tried linking another main module: {0}")]
|
#[error("Tried linking another main module: {0}")]
|
||||||
@ -69,15 +65,10 @@ pub struct LinkerPass<'map> {
|
|||||||
pub is_lib: bool,
|
pub is_lib: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
|
||||||
pub struct LinkerState {
|
|
||||||
extern_imported_types: HashMap<SourceModuleId, HashMap<String, SourceModuleId>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, LinkerState, ErrorKind>;
|
|
||||||
|
|
||||||
impl<'map> Pass for LinkerPass<'map> {
|
impl<'map> Pass for LinkerPass<'map> {
|
||||||
type Data = LinkerState;
|
type Data = ();
|
||||||
type TError = ErrorKind;
|
type TError = ErrorKind;
|
||||||
fn context(&mut self, context: &mut Context, mut state: LinkerPassState) -> PassResult {
|
fn context(&mut self, context: &mut Context, mut state: LinkerPassState) -> PassResult {
|
||||||
let mains = context
|
let mains = context
|
||||||
@ -113,16 +104,17 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
let mut modules_to_process: Vec<Rc<RefCell<_>>> = modules.values().cloned().collect();
|
let mut modules_to_process: Vec<Rc<RefCell<_>>> = modules.values().cloned().collect();
|
||||||
|
|
||||||
let mut already_imported_types = HashSet::<CustomTypeKey>::new();
|
let mut already_imported_types = HashSet::<CustomTypeKey>::new();
|
||||||
let mut already_imported_binops = HashSet::<BinopKey>::new();
|
|
||||||
|
|
||||||
while let Some(module) = modules_to_process.pop() {
|
while let Some(module) = modules_to_process.pop() {
|
||||||
let mut extern_types = HashMap::new();
|
|
||||||
let mut importer_module = module.borrow_mut();
|
let mut importer_module = module.borrow_mut();
|
||||||
|
|
||||||
for import in importer_module.imports.clone() {
|
for import in importer_module.imports.clone() {
|
||||||
let Import(path, _) = &import;
|
let Import(path, _) = &import;
|
||||||
if path.len() != 2 {
|
if path.len() != 2 {
|
||||||
state.ok::<_, Infallible>(Err(ErrorKind::InnerModulesNotYetSupported(import.clone())), import.1);
|
state.ok::<_, Infallible>(
|
||||||
|
Err(ErrorKind::InnerModulesNotYetSupported(import.clone())),
|
||||||
|
import.1,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let module_name = unsafe { path.get_unchecked(0) };
|
let module_name = unsafe { path.get_unchecked(0) };
|
||||||
@ -131,18 +123,26 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
modules.get(mod_id).unwrap()
|
modules.get(mod_id).unwrap()
|
||||||
} else if module_name == STD_NAME {
|
} else if module_name == STD_NAME {
|
||||||
let std = compile_std(&mut self.module_map)?;
|
let std = compile_std(&mut self.module_map)?;
|
||||||
modules.insert(std.module_id, Rc::new(RefCell::new(compile_std(&mut self.module_map)?)));
|
modules.insert(
|
||||||
|
std.module_id,
|
||||||
|
Rc::new(RefCell::new(compile_std(&mut self.module_map)?)),
|
||||||
|
);
|
||||||
module_ids.insert(std.name, std.module_id);
|
module_ids.insert(std.name, std.module_id);
|
||||||
modules.get(&std.module_id).unwrap()
|
modules.get(&std.module_id).unwrap()
|
||||||
} else {
|
} else {
|
||||||
let file_path = PathBuf::from(&context.base.clone()).join(module_name.to_owned() + ".reid");
|
let file_path =
|
||||||
|
PathBuf::from(&context.base.clone()).join(module_name.to_owned() + ".reid");
|
||||||
|
|
||||||
let Ok(source) = fs::read_to_string(&file_path) else {
|
let Ok(source) = fs::read_to_string(&file_path) else {
|
||||||
state.ok::<_, Infallible>(Err(ErrorKind::ModuleNotFound(module_name.clone())), import.1);
|
state.ok::<_, Infallible>(
|
||||||
|
Err(ErrorKind::ModuleNotFound(module_name.clone())),
|
||||||
|
import.1,
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let (id, tokens) = match parse_module(&source, module_name.clone(), &mut self.module_map) {
|
let (id, tokens) =
|
||||||
|
match parse_module(&source, module_name.clone(), &mut self.module_map) {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
@ -166,7 +166,8 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let module_id = imported_module.module_id;
|
let module_id = imported_module.module_id;
|
||||||
module_ids.insert(imported_module.name.clone(), imported_module.module_id);
|
module_ids
|
||||||
|
.insert(imported_module.name.clone(), imported_module.module_id);
|
||||||
modules.insert(module_id, Rc::new(RefCell::new(imported_module)));
|
modules.insert(module_id, Rc::new(RefCell::new(imported_module)));
|
||||||
let imported = modules.get_mut(&module_id).unwrap();
|
let imported = modules.get_mut(&module_id).unwrap();
|
||||||
modules_to_process.push(imported.clone());
|
modules_to_process.push(imported.clone());
|
||||||
@ -186,16 +187,28 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
}
|
}
|
||||||
.borrow_mut();
|
.borrow_mut();
|
||||||
|
|
||||||
let import_name = unsafe { path.get_unchecked(1) };
|
let func_name = unsafe { path.get_unchecked(1) };
|
||||||
|
|
||||||
let mut imported_types = Vec::new();
|
let Some(func) = imported.functions.iter_mut().find(|f| f.name == *func_name)
|
||||||
|
else {
|
||||||
|
state.ok::<_, Infallible>(
|
||||||
|
Err(ErrorKind::NoSuchFunctionInModule(
|
||||||
|
module_name.clone(),
|
||||||
|
func_name.clone(),
|
||||||
|
)),
|
||||||
|
import.1,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(func) = imported.functions.iter_mut().find(|f| f.name == *import_name) {
|
|
||||||
let func_name = func.name.clone();
|
let func_name = func.name.clone();
|
||||||
|
|
||||||
if !func.is_pub {
|
if !func.is_pub {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::FunctionIsPrivate(module_name.clone(), func_name.clone())),
|
Err(ErrorKind::FunctionIsPrivate(
|
||||||
|
module_name.clone(),
|
||||||
|
func_name.clone(),
|
||||||
|
)),
|
||||||
import.1,
|
import.1,
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
@ -203,7 +216,11 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
|
|
||||||
func.is_imported = true;
|
func.is_imported = true;
|
||||||
|
|
||||||
if let Some(existing) = importer_module.functions.iter().find(|f| f.name == *func_name) {
|
if let Some(existing) = importer_module
|
||||||
|
.functions
|
||||||
|
.iter()
|
||||||
|
.find(|f| f.name == *func_name)
|
||||||
|
{
|
||||||
if let Err(e) = existing.equals_as_imported(func) {
|
if let Err(e) = existing.equals_as_imported(func) {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::FunctionImportIssue(
|
Err(ErrorKind::FunctionImportIssue(
|
||||||
@ -216,251 +233,32 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let types = import_type(&func.return_type, false);
|
fn import_type(ty: &TypeKind) -> Vec<CustomTypeKey> {
|
||||||
|
let mut imported_types = Vec::new();
|
||||||
|
match &ty {
|
||||||
|
TypeKind::CustomType(key) => imported_types.push(key.clone()),
|
||||||
|
TypeKind::Borrow(ty, _) => imported_types.extend(import_type(ty)),
|
||||||
|
TypeKind::Array(ty, _) => imported_types.extend(import_type(ty)),
|
||||||
|
TypeKind::UserPtr(ty) => imported_types.extend(import_type(ty)),
|
||||||
|
TypeKind::CodegenPtr(ty) => imported_types.extend(import_type(ty)),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
imported_types
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut imported_types = Vec::new();
|
||||||
|
|
||||||
|
let types = import_type(&func.return_type);
|
||||||
let return_type = func.return_type.clone();
|
let return_type = func.return_type.clone();
|
||||||
imported_types.extend(types);
|
imported_types.extend(types);
|
||||||
|
|
||||||
let mut param_tys = Vec::new();
|
let mut param_tys = Vec::new();
|
||||||
for (param_name, param_ty) in &func.parameters {
|
for (param_name, param_ty) in &func.parameters {
|
||||||
let types = import_type(¶m_ty, false);
|
let types = import_type(¶m_ty);
|
||||||
imported_types.extend(types);
|
imported_types.extend(types);
|
||||||
param_tys.push((param_name.clone(), param_ty.clone()));
|
param_tys.push((param_name.clone(), param_ty.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
importer_module.functions.push(FunctionDefinition {
|
|
||||||
name: func_name,
|
|
||||||
is_pub: false,
|
|
||||||
is_imported: false,
|
|
||||||
return_type,
|
|
||||||
parameters: param_tys,
|
|
||||||
kind: super::FunctionDefinitionKind::Extern(true),
|
|
||||||
});
|
|
||||||
} else if let Some(ty) = imported.typedefs.iter_mut().find(|f| f.name == *import_name) {
|
|
||||||
let external_key = CustomTypeKey(ty.name.clone(), ty.source_module);
|
|
||||||
let imported_ty = TypeKind::CustomType(external_key.clone());
|
|
||||||
imported_types.push((external_key, true));
|
|
||||||
|
|
||||||
for binop in &mut imported.binop_defs {
|
|
||||||
if binop.lhs.1 != imported_ty && binop.rhs.1 != imported_ty {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let binop_key = BinopKey {
|
|
||||||
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
|
||||||
operator: binop.op,
|
|
||||||
};
|
|
||||||
if already_imported_binops.contains(&binop_key) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
binop.exported = true;
|
|
||||||
already_imported_binops.insert(binop_key);
|
|
||||||
match &binop.fn_kind {
|
|
||||||
FunctionDefinitionKind::Local(block, metadata) => {
|
|
||||||
importer_module.binop_defs.push(BinopDefinition {
|
|
||||||
lhs: binop.lhs.clone(),
|
|
||||||
op: binop.op,
|
|
||||||
rhs: binop.rhs.clone(),
|
|
||||||
return_type: binop.return_type.clone(),
|
|
||||||
fn_kind: FunctionDefinitionKind::Extern(true),
|
|
||||||
meta: binop.meta.clone(),
|
|
||||||
exported: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
FunctionDefinitionKind::Extern(_) => {}
|
|
||||||
FunctionDefinitionKind::Intrinsic(_) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state.ok::<_, Infallible>(
|
|
||||||
Err(ErrorKind::ImportDoesNotExist(module_name.clone(), import_name.clone())),
|
|
||||||
import.1,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut seen = HashSet::new();
|
|
||||||
let mut current_extern_types = HashSet::new();
|
|
||||||
seen.extend(imported_types.clone().iter().map(|t| t.0.clone()));
|
|
||||||
current_extern_types.extend(imported_types.clone().iter().filter(|t| t.1).map(|t| t.0.clone()));
|
|
||||||
for extern_type in ¤t_extern_types {
|
|
||||||
extern_types.insert(extern_type.0.clone(), extern_type.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let imported_mod_id = imported.module_id;
|
|
||||||
let imported_mod_typedefs = &mut imported.typedefs;
|
|
||||||
|
|
||||||
for typekey in imported_types.clone() {
|
|
||||||
let typedef = imported_mod_typedefs
|
|
||||||
.iter()
|
|
||||||
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey.0)
|
|
||||||
.unwrap();
|
|
||||||
let inner = find_inner_types(typedef, seen.clone(), imported_mod_id);
|
|
||||||
seen.extend(inner.iter().cloned());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Unable to import same-named type from multiple places..
|
|
||||||
let seen = seen
|
|
||||||
.difference(&already_imported_types)
|
|
||||||
.cloned()
|
|
||||||
.collect::<HashSet<_>>();
|
|
||||||
|
|
||||||
already_imported_types.extend(seen.clone());
|
|
||||||
|
|
||||||
for typekey in &already_imported_types {
|
|
||||||
if current_extern_types.contains(typekey) {
|
|
||||||
let module_id = importer_module.module_id;
|
|
||||||
let typedef = importer_module
|
|
||||||
.typedefs
|
|
||||||
.iter_mut()
|
|
||||||
.find(|t| t.name == typekey.0 && t.source_module == typekey.1);
|
|
||||||
if let Some(typedef) = typedef {
|
|
||||||
typedef.importer = Some(module_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for typekey in seen.into_iter() {
|
|
||||||
let mut typedef = imported_mod_typedefs
|
|
||||||
.iter()
|
|
||||||
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey)
|
|
||||||
.unwrap()
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
if current_extern_types.contains(&typekey) {
|
|
||||||
typedef = TypeDefinition {
|
|
||||||
importer: Some(importer_module.module_id),
|
|
||||||
..typedef
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
importer_module.typedefs.push(typedef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state
|
|
||||||
.scope
|
|
||||||
.data
|
|
||||||
.extern_imported_types
|
|
||||||
.insert(importer_module.module_id, extern_types);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut modules: Vec<Module> = modules
|
|
||||||
.into_values()
|
|
||||||
.map(|v| Rc::into_inner(v).unwrap().into_inner())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
for module in modules.drain(..) {
|
|
||||||
context.modules.insert(module.module_id, module);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn function(
|
|
||||||
&mut self,
|
|
||||||
function: &mut FunctionDefinition,
|
|
||||||
state: PassState<Self::Data, Self::TError>,
|
|
||||||
) -> PassResult {
|
|
||||||
if matches!(function.kind, FunctionDefinitionKind::Local(_, _)) {
|
|
||||||
let mod_id = state.scope.module_id.unwrap();
|
|
||||||
let extern_types = &state.scope.data.extern_imported_types.get(&mod_id);
|
|
||||||
if let Some(extern_types) = extern_types {
|
|
||||||
function.return_type = function.return_type.update_imported(*extern_types, mod_id);
|
|
||||||
for param in function.parameters.iter_mut() {
|
|
||||||
param.1 = param.1.update_imported(extern_types, mod_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stmt(&mut self, stmt: &mut super::Statement, state: PassState<Self::Data, Self::TError>) -> PassResult {
|
|
||||||
let mod_id = state.scope.module_id.unwrap();
|
|
||||||
let extern_types = &state.scope.data.extern_imported_types.get(&mod_id);
|
|
||||||
if let Some(extern_types) = extern_types {
|
|
||||||
match &mut stmt.0 {
|
|
||||||
super::StmtKind::Let(var_ref, _, _) => {
|
|
||||||
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expr(&mut self, expr: &mut super::Expression, state: PassState<Self::Data, Self::TError>) -> PassResult {
|
|
||||||
let mod_id = state.scope.module_id.unwrap();
|
|
||||||
let extern_types = &state.scope.data.extern_imported_types.get(&mod_id);
|
|
||||||
if let Some(extern_types) = extern_types {
|
|
||||||
match &mut expr.0 {
|
|
||||||
super::ExprKind::Variable(var_ref) => {
|
|
||||||
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
|
||||||
}
|
|
||||||
super::ExprKind::Indexed(.., type_kind, _) => {
|
|
||||||
*type_kind = type_kind.update_imported(extern_types, mod_id)
|
|
||||||
}
|
|
||||||
super::ExprKind::Accessed(.., type_kind, _) => {
|
|
||||||
*type_kind = type_kind.update_imported(extern_types, mod_id)
|
|
||||||
}
|
|
||||||
super::ExprKind::BinOp(.., type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id),
|
|
||||||
|
|
||||||
super::ExprKind::Borrow(var_ref, _) => {
|
|
||||||
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
|
||||||
}
|
|
||||||
super::ExprKind::Deref(var_ref) => {
|
|
||||||
var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
|
|
||||||
}
|
|
||||||
super::ExprKind::CastTo(_, type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeKind {
|
|
||||||
fn update_imported(
|
|
||||||
&self,
|
|
||||||
extern_types: &HashMap<String, SourceModuleId>,
|
|
||||||
importer_mod_id: SourceModuleId,
|
|
||||||
) -> TypeKind {
|
|
||||||
match &self {
|
|
||||||
TypeKind::Array(type_kind, len) => {
|
|
||||||
TypeKind::Array(Box::new(type_kind.update_imported(extern_types, importer_mod_id)), *len)
|
|
||||||
}
|
|
||||||
TypeKind::CustomType(custom_type_key) => {
|
|
||||||
if let Some(mod_id) = extern_types.get(&custom_type_key.0) {
|
|
||||||
TypeKind::CustomType(CustomTypeKey(custom_type_key.0.clone(), *mod_id))
|
|
||||||
} else {
|
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeKind::Borrow(type_kind, mutable) => TypeKind::Borrow(
|
|
||||||
Box::new(type_kind.update_imported(extern_types, importer_mod_id)),
|
|
||||||
*mutable,
|
|
||||||
),
|
|
||||||
TypeKind::UserPtr(type_kind) => {
|
|
||||||
TypeKind::UserPtr(Box::new(type_kind.update_imported(extern_types, importer_mod_id)))
|
|
||||||
}
|
|
||||||
TypeKind::CodegenPtr(type_kind) => {
|
|
||||||
TypeKind::CodegenPtr(Box::new(type_kind.update_imported(extern_types, importer_mod_id)))
|
|
||||||
}
|
|
||||||
_ => self.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn import_type(ty: &TypeKind, usable_import: bool) -> Vec<(CustomTypeKey, bool)> {
|
|
||||||
let mut imported_types = Vec::new();
|
|
||||||
match &ty {
|
|
||||||
TypeKind::CustomType(key) => imported_types.push((key.clone(), usable_import)),
|
|
||||||
TypeKind::Borrow(ty, _) => imported_types.extend(import_type(ty, usable_import)),
|
|
||||||
TypeKind::Array(ty, _) => imported_types.extend(import_type(ty, usable_import)),
|
|
||||||
TypeKind::UserPtr(ty) => imported_types.extend(import_type(ty, usable_import)),
|
|
||||||
TypeKind::CodegenPtr(ty) => imported_types.extend(import_type(ty, usable_import)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
imported_types
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_inner_types(
|
fn find_inner_types(
|
||||||
typedef: &TypeDefinition,
|
typedef: &TypeDefinition,
|
||||||
mut seen: HashSet<CustomTypeKey>,
|
mut seen: HashSet<CustomTypeKey>,
|
||||||
@ -492,3 +290,60 @@ fn find_inner_types(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
seen.extend(imported_types.clone());
|
||||||
|
|
||||||
|
let imported_mod_id = imported.module_id;
|
||||||
|
let imported_mod_typedefs = &mut imported.typedefs;
|
||||||
|
|
||||||
|
for typekey in imported_types.clone() {
|
||||||
|
let typedef = imported_mod_typedefs
|
||||||
|
.iter()
|
||||||
|
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey)
|
||||||
|
.unwrap();
|
||||||
|
let inner = find_inner_types(typedef, seen.clone(), imported_mod_id);
|
||||||
|
seen.extend(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Unable to import same-named type from multiple places..
|
||||||
|
let seen = seen
|
||||||
|
.difference(&already_imported_types)
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
|
already_imported_types.extend(seen.clone());
|
||||||
|
|
||||||
|
for typekey in seen.into_iter() {
|
||||||
|
let typedef = imported_mod_typedefs
|
||||||
|
.iter()
|
||||||
|
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey)
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
importer_module.typedefs.push(typedef.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
importer_module.functions.push(FunctionDefinition {
|
||||||
|
name: func_name,
|
||||||
|
is_pub: false,
|
||||||
|
is_imported: false,
|
||||||
|
return_type,
|
||||||
|
parameters: param_tys,
|
||||||
|
kind: super::FunctionDefinitionKind::Extern(true),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut modules: Vec<Module> = modules
|
||||||
|
.into_values()
|
||||||
|
.map(|v| Rc::into_inner(v).unwrap().into_inner())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for module in modules.drain(..) {
|
||||||
|
context.modules.insert(module.module_id, module);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -354,7 +354,6 @@ pub struct TypeDefinition {
|
|||||||
pub kind: TypeDefinitionKind,
|
pub kind: TypeDefinitionKind,
|
||||||
pub meta: Metadata,
|
pub meta: Metadata,
|
||||||
pub source_module: SourceModuleId,
|
pub source_module: SourceModuleId,
|
||||||
pub importer: Option<SourceModuleId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -370,8 +369,6 @@ pub struct BinopDefinition {
|
|||||||
pub return_type: TypeKind,
|
pub return_type: TypeKind,
|
||||||
pub fn_kind: FunctionDefinitionKind,
|
pub fn_kind: FunctionDefinitionKind,
|
||||||
pub meta: Metadata,
|
pub meta: Metadata,
|
||||||
// Wether this binop definition has been imported into another module.
|
|
||||||
pub exported: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BinopDefinition {
|
impl BinopDefinition {
|
||||||
|
@ -117,11 +117,10 @@ impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BinopMap = Storage<BinopKey, ScopeBinopDef>;
|
pub type BinopMap = Storage<ScopeBinopKey, ScopeBinopDef>;
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug)]
|
#[derive(Clone, Default, Debug)]
|
||||||
pub struct Scope<Data: Clone + Default> {
|
pub struct Scope<Data: Clone + Default> {
|
||||||
pub module_id: Option<SourceModuleId>,
|
|
||||||
pub binops: BinopMap,
|
pub binops: BinopMap,
|
||||||
pub function_returns: Storage<String, ScopeFunction>,
|
pub function_returns: Storage<String, ScopeFunction>,
|
||||||
pub variables: Storage<String, ScopeVariable>,
|
pub variables: Storage<String, ScopeVariable>,
|
||||||
@ -134,7 +133,6 @@ pub struct Scope<Data: Clone + Default> {
|
|||||||
impl<Data: Clone + Default> Scope<Data> {
|
impl<Data: Clone + Default> Scope<Data> {
|
||||||
pub fn inner(&self) -> Scope<Data> {
|
pub fn inner(&self) -> Scope<Data> {
|
||||||
Scope {
|
Scope {
|
||||||
module_id: self.module_id,
|
|
||||||
function_returns: self.function_returns.clone(),
|
function_returns: self.function_returns.clone(),
|
||||||
variables: self.variables.clone(),
|
variables: self.variables.clone(),
|
||||||
binops: self.binops.clone(),
|
binops: self.binops.clone(),
|
||||||
@ -158,15 +156,6 @@ impl<Data: Clone + Default> Scope<Data> {
|
|||||||
.find(|(CustomTypeKey(n, _), _)| n == name)
|
.find(|(CustomTypeKey(n, _), _)| n == name)
|
||||||
.map(|(key, _)| key)
|
.map(|(key, _)| key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_type(&self, typekey: &CustomTypeKey) -> Option<&TypeDefinition> {
|
|
||||||
self.types.get(&typekey).or(self
|
|
||||||
.types
|
|
||||||
.0
|
|
||||||
.iter()
|
|
||||||
.find(|(key, def)| key.0 == typekey.0 && def.importer == Some(typekey.1))
|
|
||||||
.map(|(_, v)| v))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -182,7 +171,7 @@ pub struct ScopeVariable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq)]
|
#[derive(Clone, Debug, Eq)]
|
||||||
pub struct BinopKey {
|
pub struct ScopeBinopKey {
|
||||||
pub params: (TypeKind, TypeKind),
|
pub params: (TypeKind, TypeKind),
|
||||||
pub operator: BinaryOperator,
|
pub operator: BinaryOperator,
|
||||||
}
|
}
|
||||||
@ -194,7 +183,7 @@ pub enum CommutativeKind {
|
|||||||
Any,
|
Any,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for BinopKey {
|
impl PartialEq for ScopeBinopKey {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
if self.operator != other.operator {
|
if self.operator != other.operator {
|
||||||
return false;
|
return false;
|
||||||
@ -216,7 +205,7 @@ impl PartialEq for BinopKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::hash::Hash for BinopKey {
|
impl std::hash::Hash for ScopeBinopKey {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
if self.operator.is_commutative() {
|
if self.operator.is_commutative() {
|
||||||
let mut sorted = vec![&self.params.0, &self.params.1];
|
let mut sorted = vec![&self.params.0, &self.params.1];
|
||||||
@ -336,7 +325,7 @@ impl Context {
|
|||||||
scope
|
scope
|
||||||
.binops
|
.binops
|
||||||
.set(
|
.set(
|
||||||
BinopKey {
|
ScopeBinopKey {
|
||||||
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
|
||||||
operator: intrinsic.op,
|
operator: intrinsic.op,
|
||||||
},
|
},
|
||||||
@ -358,8 +347,6 @@ impl Context {
|
|||||||
|
|
||||||
impl Module {
|
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 {
|
||||||
scope.module_id = Some(self.module_id);
|
|
||||||
|
|
||||||
for typedef in &self.typedefs {
|
for typedef in &self.typedefs {
|
||||||
scope
|
scope
|
||||||
.types
|
.types
|
||||||
@ -374,7 +361,7 @@ impl Module {
|
|||||||
scope
|
scope
|
||||||
.binops
|
.binops
|
||||||
.set(
|
.set(
|
||||||
BinopKey {
|
ScopeBinopKey {
|
||||||
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||||
operator: binop.op,
|
operator: binop.op,
|
||||||
},
|
},
|
||||||
|
@ -300,7 +300,8 @@ impl TypeKind {
|
|||||||
TypeKind::CustomType(custom_type_key) => {
|
TypeKind::CustomType(custom_type_key) => {
|
||||||
state
|
state
|
||||||
.scope
|
.scope
|
||||||
.get_type(custom_type_key)
|
.types
|
||||||
|
.get(custom_type_key)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.ok_or(ErrorKind::NoSuchType(
|
.ok_or(ErrorKind::NoSuchType(
|
||||||
custom_type_key.0.clone(),
|
custom_type_key.0.clone(),
|
||||||
|
@ -34,7 +34,12 @@ impl<'t> Pass for TypeCheck<'t> {
|
|||||||
fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) -> PassResult {
|
fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) -> PassResult {
|
||||||
let mut defmap = HashMap::new();
|
let mut defmap = HashMap::new();
|
||||||
for typedef in &module.typedefs {
|
for typedef in &module.typedefs {
|
||||||
let TypeDefinition { name, kind, meta, .. } = &typedef;
|
let TypeDefinition {
|
||||||
|
name,
|
||||||
|
kind,
|
||||||
|
meta,
|
||||||
|
source_module: _,
|
||||||
|
} = &typedef;
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
TypeDefinitionKind::Struct(StructType(fields)) => {
|
||||||
@ -50,12 +55,10 @@ impl<'t> Pass for TypeCheck<'t> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if typedef.source_module == module.module_id || typedef.importer == Some(module.module_id) {
|
|
||||||
if let Some(_) = defmap.insert(&typedef.name, typedef) {
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for typedef in defmap.values() {
|
for typedef in defmap.values() {
|
||||||
let mut seen_types = HashSet::new();
|
let mut seen_types = HashSet::new();
|
||||||
@ -214,6 +217,8 @@ impl Block {
|
|||||||
variable_reference.2,
|
variable_reference.2,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
dbg!(&var_t_resolved);
|
||||||
|
|
||||||
// Typecheck (and coerce) expression with said type
|
// Typecheck (and coerce) expression with said type
|
||||||
let res = expression.typecheck(&mut state, &typerefs, HintKind::Coerce(var_t_resolved.clone()));
|
let res = expression.typecheck(&mut state, &typerefs, HintKind::Coerce(var_t_resolved.clone()));
|
||||||
// If expression resolution itself was erronous, resolve as
|
// If expression resolution itself was erronous, resolve as
|
||||||
@ -422,7 +427,7 @@ impl Expression {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
let binops = state.scope.binops.filter(&pass::BinopKey {
|
let binops = state.scope.binops.filter(&pass::ScopeBinopKey {
|
||||||
params: (lhs_type.clone(), rhs_type.clone()),
|
params: (lhs_type.clone(), rhs_type.clone()),
|
||||||
operator: *op,
|
operator: *op,
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,7 @@ use crate::{
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{
|
||||||
pass::{BinopKey, Pass, PassResult, PassState},
|
pass::{Pass, PassResult, PassState, ScopeBinopKey},
|
||||||
TypeKind::*,
|
TypeKind::*,
|
||||||
VagueType::*,
|
VagueType::*,
|
||||||
},
|
},
|
||||||
@ -33,7 +33,7 @@ use super::{
|
|||||||
/// TypeRefs-struct is used as a helper to go through the modules and change
|
/// TypeRefs-struct is used as a helper to go through the modules and change
|
||||||
/// types while inferring.
|
/// types while inferring.
|
||||||
pub struct TypeInference<'t> {
|
pub struct TypeInference<'t> {
|
||||||
pub refs: &'t mut TypeRefs,
|
pub refs: &'t TypeRefs,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Pass for TypeInference<'t> {
|
impl<'t> Pass for TypeInference<'t> {
|
||||||
@ -62,7 +62,7 @@ impl<'t> Pass for TypeInference<'t> {
|
|||||||
|
|
||||||
let mut seen_binops = HashSet::new();
|
let mut seen_binops = HashSet::new();
|
||||||
for binop in &module.binop_defs {
|
for binop in &module.binop_defs {
|
||||||
let binop_key = BinopKey {
|
let binop_key = ScopeBinopKey {
|
||||||
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
||||||
operator: binop.op,
|
operator: binop.op,
|
||||||
};
|
};
|
||||||
@ -77,18 +77,7 @@ impl<'t> Pass for TypeInference<'t> {
|
|||||||
binop.signature(),
|
binop.signature(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
seen_binops.insert(binop_key.clone());
|
seen_binops.insert(binop_key);
|
||||||
self.refs
|
|
||||||
.binop_types
|
|
||||||
.set(
|
|
||||||
binop_key,
|
|
||||||
crate::mir::pass::ScopeBinopDef {
|
|
||||||
hands: (binop.lhs.1.clone(), binop.rhs.1.clone()),
|
|
||||||
operator: binop.op,
|
|
||||||
return_ty: binop.return_type.clone(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +119,7 @@ impl BinopDefinition {
|
|||||||
.fn_kind
|
.fn_kind
|
||||||
.infer_types(state, &scope_hints, Some(self.return_type.clone()))?;
|
.infer_types(state, &scope_hints, Some(self.return_type.clone()))?;
|
||||||
if let Some(mut ret_ty) = ret_ty {
|
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());
|
ret_ty.narrow(&scope_hints.from_type(&self.return_type).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +320,7 @@ impl Expression {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if binop.operator.is_commutative() {
|
if binop.operator.is_commutative() {
|
||||||
if let Some(_) = binop.narrow(&rhs_ty, &lhs_ty) {
|
if let Some(_) = binop.narrow(&lhs_ty, &rhs_ty) {
|
||||||
applying_binops.push(binop.clone());
|
applying_binops.push(binop.clone());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -340,6 +330,7 @@ impl Expression {
|
|||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
if binops.len() > 0 {
|
if binops.len() > 0 {
|
||||||
let binop = unsafe { binops.get_unchecked(0) };
|
let binop = unsafe { binops.get_unchecked(0) };
|
||||||
let mut widened_lhs = binop.hands.0.clone();
|
let mut widened_lhs = binop.hands.0.clone();
|
||||||
|
@ -10,7 +10,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::pass::{BinopKey, ScopeBinopDef, Storage},
|
super::pass::{ScopeBinopDef, ScopeBinopKey, Storage},
|
||||||
ErrorKind,
|
ErrorKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ impl TypeRefKind {
|
|||||||
while let Some(other) = binops.next() {
|
while let Some(other) = binops.next() {
|
||||||
ty = ty.widen_into(&other);
|
ty = ty.widen_into(&other);
|
||||||
}
|
}
|
||||||
ty.clone()
|
ty
|
||||||
} else {
|
} else {
|
||||||
TypeKind::Vague(VagueType::Unknown)
|
TypeKind::Vague(VagueType::Unknown)
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,9 @@ fn test(source: &str, name: &str, expected_exit_code: Option<i32>) {
|
|||||||
let time = SystemTime::now();
|
let time = SystemTime::now();
|
||||||
let in_path = PathBuf::from(format!(
|
let in_path = PathBuf::from(format!(
|
||||||
"/tmp/temp-{}.o",
|
"/tmp/temp-{}.o",
|
||||||
time.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_nanos()
|
time.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos()
|
||||||
));
|
));
|
||||||
|
|
||||||
std::fs::write(&in_path, &output.obj_buffer).expect("Could not write OBJ-file!");
|
std::fs::write(&in_path, &output.obj_buffer).expect("Could not write OBJ-file!");
|
||||||
@ -58,11 +60,19 @@ fn test(source: &str, name: &str, expected_exit_code: Option<i32>) {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn arithmetic_compiles_well() {
|
fn arithmetic_compiles_well() {
|
||||||
test(include_str!("../../examples/arithmetic.reid"), "test", Some(48));
|
test(
|
||||||
|
include_str!("../../examples/arithmetic.reid"),
|
||||||
|
"test",
|
||||||
|
Some(48),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn array_structs_compiles_well() {
|
fn array_structs_compiles_well() {
|
||||||
test(include_str!("../../examples/array_structs.reid"), "test", Some(5));
|
test(
|
||||||
|
include_str!("../../examples/array_structs.reid"),
|
||||||
|
"test",
|
||||||
|
Some(5),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn array_compiles_well() {
|
fn array_compiles_well() {
|
||||||
@ -74,7 +84,11 @@ fn borrow_compiles_well() {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn borrow_hard_compiles_well() {
|
fn borrow_hard_compiles_well() {
|
||||||
test(include_str!("../../examples/borrow_hard.reid"), "test", Some(17));
|
test(
|
||||||
|
include_str!("../../examples/borrow_hard.reid"),
|
||||||
|
"test",
|
||||||
|
Some(17),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn cast_compiles_well() {
|
fn cast_compiles_well() {
|
||||||
@ -86,11 +100,19 @@ fn char_compiles_well() {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn div_mod_compiles_well() {
|
fn div_mod_compiles_well() {
|
||||||
test(include_str!("../../examples/div_mod.reid"), "test", Some(12));
|
test(
|
||||||
|
include_str!("../../examples/div_mod.reid"),
|
||||||
|
"test",
|
||||||
|
Some(12),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn fibonacci_compiles_well() {
|
fn fibonacci_compiles_well() {
|
||||||
test(include_str!("../../examples/fibonacci.reid"), "test", Some(1));
|
test(
|
||||||
|
include_str!("../../examples/fibonacci.reid"),
|
||||||
|
"test",
|
||||||
|
Some(1),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn float_compiles_well() {
|
fn float_compiles_well() {
|
||||||
@ -98,11 +120,19 @@ fn float_compiles_well() {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn hello_world_compiles_well() {
|
fn hello_world_compiles_well() {
|
||||||
test(include_str!("../../examples/hello_world.reid"), "test", None);
|
test(
|
||||||
|
include_str!("../../examples/hello_world.reid"),
|
||||||
|
"test",
|
||||||
|
None,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn mutable_compiles_well() {
|
fn mutable_compiles_well() {
|
||||||
test(include_str!("../../examples/mutable.reid"), "test", Some(21));
|
test(
|
||||||
|
include_str!("../../examples/mutable.reid"),
|
||||||
|
"test",
|
||||||
|
Some(21),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn ptr_compiles_well() {
|
fn ptr_compiles_well() {
|
||||||
@ -110,7 +140,11 @@ fn ptr_compiles_well() {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn std_test_compiles_well() {
|
fn std_test_compiles_well() {
|
||||||
test(include_str!("../../examples/std_test.reid"), "test", Some(3));
|
test(
|
||||||
|
include_str!("../../examples/std_test.reid"),
|
||||||
|
"test",
|
||||||
|
Some(3),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn strings_compiles_well() {
|
fn strings_compiles_well() {
|
||||||
@ -126,22 +160,34 @@ fn loops_compiles_well() {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn ptr_hard_compiles_well() {
|
fn ptr_hard_compiles_well() {
|
||||||
test(include_str!("../../examples/ptr_hard.reid"), "test", Some(0));
|
test(
|
||||||
|
include_str!("../../examples/ptr_hard.reid"),
|
||||||
|
"test",
|
||||||
|
Some(0),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn loop_hard_compiles_well() {
|
fn loop_hard_compiles_well() {
|
||||||
test(include_str!("../../examples/loop_hard.reid"), "test", Some(0));
|
test(
|
||||||
|
include_str!("../../examples/loop_hard.reid"),
|
||||||
|
"test",
|
||||||
|
Some(0),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn custom_binop_compiles_well() {
|
fn custom_binop_compiles_well() {
|
||||||
test(include_str!("../../examples/custom_binop.reid"), "test", Some(21));
|
test(
|
||||||
|
include_str!("../../examples/custom_binop.reid"),
|
||||||
|
"test",
|
||||||
|
Some(21),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn array_short_compiles_well() {
|
fn array_short_compiles_well() {
|
||||||
test(include_str!("../../examples/array_short.reid"), "test", Some(5));
|
test(
|
||||||
}
|
include_str!("../../examples/array_short.reid"),
|
||||||
#[test]
|
"test",
|
||||||
fn imported_type_compiles_well() {
|
Some(5),
|
||||||
test(include_str!("../../examples/imported_type.reid"), "test", Some(0));
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user