Allow importing types
This commit is contained in:
parent
12e2851a8b
commit
269de327b8
@ -1,6 +1,12 @@
|
||||
pub fn abs(f: f32) -> f32 {
|
||||
if f < 0.0 {
|
||||
return f * (0.0 - 1.0);
|
||||
}
|
||||
return f;
|
||||
|
||||
import std::print;
|
||||
import std::new_string;
|
||||
import std::String;
|
||||
|
||||
fn otus() -> String {
|
||||
return new_string();
|
||||
}
|
||||
|
||||
fn main() -> u8 {
|
||||
return 0;
|
||||
}
|
469
foo.reid
469
foo.reid
@ -1,469 +0,0 @@
|
||||
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);
|
||||
}
|
@ -95,6 +95,7 @@ impl ast::Module {
|
||||
},
|
||||
meta: (*range).as_meta(module_id),
|
||||
source_module: module_id,
|
||||
importer: None,
|
||||
};
|
||||
typedefs.push(def);
|
||||
}
|
||||
|
@ -75,7 +75,17 @@ impl Display for BinopDefinition {
|
||||
|
||||
impl Display for TypeDefinition {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "type {} = ", self.name)?;
|
||||
write!(
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ pub enum ErrorKind {
|
||||
ModuleNotFound(String),
|
||||
#[error("Error while compiling module {0}: {1}")]
|
||||
ModuleCompilationError(String, String),
|
||||
#[error("No such function {0} found in module {1}")]
|
||||
NoSuchFunctionInModule(String, String),
|
||||
#[error("No such value {0} found in module {1}")]
|
||||
ImportDoesNotExist(String, String),
|
||||
#[error("Importing function {0}::{1} not possible: {2}")]
|
||||
FunctionImportIssue(String, String, EqualsIssue),
|
||||
#[error("Tried linking another main module: {0}")]
|
||||
@ -111,10 +111,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
for import in importer_module.imports.clone() {
|
||||
let Import(path, _) = &import;
|
||||
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) };
|
||||
@ -123,38 +120,30 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
modules.get(mod_id).unwrap()
|
||||
} else if module_name == STD_NAME {
|
||||
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);
|
||||
modules.get(&std.module_id).unwrap()
|
||||
} 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 {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::ModuleNotFound(module_name.clone())),
|
||||
import.1,
|
||||
);
|
||||
state.ok::<_, Infallible>(Err(ErrorKind::ModuleNotFound(module_name.clone())), import.1);
|
||||
continue;
|
||||
};
|
||||
|
||||
let (id, tokens) =
|
||||
match parse_module(&source, module_name.clone(), &mut self.module_map) {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::ModuleCompilationError(
|
||||
module_name.clone(),
|
||||
format!("{}", err),
|
||||
)),
|
||||
import.1,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let (id, tokens) = match parse_module(&source, module_name.clone(), &mut self.module_map) {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::ModuleCompilationError(
|
||||
module_name.clone(),
|
||||
format!("{}", err),
|
||||
)),
|
||||
import.1,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) {
|
||||
Ok(imported_module) => {
|
||||
@ -166,8 +155,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
continue;
|
||||
}
|
||||
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)));
|
||||
let imported = modules.get_mut(&module_id).unwrap();
|
||||
modules_to_process.push(imported.clone());
|
||||
@ -187,112 +175,74 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
}
|
||||
.borrow_mut();
|
||||
|
||||
let func_name = unsafe { path.get_unchecked(1) };
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
let func_name = func.name.clone();
|
||||
|
||||
if !func.is_pub {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::FunctionIsPrivate(
|
||||
module_name.clone(),
|
||||
func_name.clone(),
|
||||
)),
|
||||
import.1,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
func.is_imported = true;
|
||||
|
||||
if let Some(existing) = importer_module
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.name == *func_name)
|
||||
{
|
||||
if let Err(e) = existing.equals_as_imported(func) {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::FunctionImportIssue(
|
||||
module_name.clone(),
|
||||
func_name.clone(),
|
||||
e,
|
||||
)),
|
||||
import.1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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 import_name = unsafe { path.get_unchecked(1) };
|
||||
|
||||
let mut imported_types = Vec::new();
|
||||
|
||||
let types = import_type(&func.return_type);
|
||||
let return_type = func.return_type.clone();
|
||||
imported_types.extend(types);
|
||||
if let Some(func) = imported.functions.iter_mut().find(|f| f.name == *import_name) {
|
||||
let func_name = func.name.clone();
|
||||
|
||||
let mut param_tys = Vec::new();
|
||||
for (param_name, param_ty) in &func.parameters {
|
||||
let types = import_type(¶m_ty);
|
||||
imported_types.extend(types);
|
||||
param_tys.push((param_name.clone(), param_ty.clone()));
|
||||
}
|
||||
if !func.is_pub {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::FunctionIsPrivate(module_name.clone(), func_name.clone())),
|
||||
import.1,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
fn find_inner_types(
|
||||
typedef: &TypeDefinition,
|
||||
mut seen: HashSet<CustomTypeKey>,
|
||||
mod_id: SourceModuleId,
|
||||
) -> Vec<CustomTypeKey> {
|
||||
match &typedef.kind {
|
||||
crate::mir::TypeDefinitionKind::Struct(struct_type) => {
|
||||
let typenames = struct_type
|
||||
.0
|
||||
.iter()
|
||||
.filter(|t| matches!(t.1, TypeKind::CustomType(..)))
|
||||
.map(|t| match &t.1 {
|
||||
TypeKind::CustomType(CustomTypeKey(t, _)) => t,
|
||||
_ => panic!(),
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
func.is_imported = true;
|
||||
|
||||
for typename in typenames {
|
||||
if seen.contains(&CustomTypeKey(typename.clone(), mod_id)) {
|
||||
continue;
|
||||
}
|
||||
let inner = find_inner_types(typedef, seen.clone(), mod_id);
|
||||
seen.insert(CustomTypeKey(typename, mod_id));
|
||||
seen.extend(inner);
|
||||
}
|
||||
|
||||
seen.into_iter().collect()
|
||||
if let Some(existing) = importer_module.functions.iter().find(|f| f.name == *func_name) {
|
||||
if let Err(e) = existing.equals_as_imported(func) {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::FunctionImportIssue(
|
||||
module_name.clone(),
|
||||
func_name.clone(),
|
||||
e,
|
||||
)),
|
||||
import.1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let types = import_type(&func.return_type, false);
|
||||
let return_type = func.return_type.clone();
|
||||
imported_types.extend(types);
|
||||
|
||||
let mut param_tys = Vec::new();
|
||||
for (param_name, param_ty) in &func.parameters {
|
||||
let types = import_type(¶m_ty, false);
|
||||
imported_types.extend(types);
|
||||
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) {
|
||||
dbg!("hello??");
|
||||
let external_key = CustomTypeKey(ty.name.clone(), ty.source_module);
|
||||
imported_types.push((external_key, true));
|
||||
dbg!(&imported_types);
|
||||
} else {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::ImportDoesNotExist(module_name.clone(), import_name.clone())),
|
||||
import.1,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut seen = HashSet::new();
|
||||
seen.extend(imported_types.clone());
|
||||
let mut extern_types = HashSet::new();
|
||||
seen.extend(imported_types.clone().iter().map(|t| t.0.clone()));
|
||||
extern_types.extend(imported_types.clone().iter().filter(|t| t.1).map(|t| t.0.clone()));
|
||||
dbg!(&imported_types);
|
||||
dbg!(&extern_types);
|
||||
|
||||
let imported_mod_id = imported.module_id;
|
||||
let imported_mod_typedefs = &mut imported.typedefs;
|
||||
@ -300,10 +250,10 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
for typekey in imported_types.clone() {
|
||||
let typedef = imported_mod_typedefs
|
||||
.iter()
|
||||
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey)
|
||||
.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);
|
||||
seen.extend(inner.iter().cloned());
|
||||
}
|
||||
|
||||
// TODO: Unable to import same-named type from multiple places..
|
||||
@ -314,24 +264,37 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
|
||||
already_imported_types.extend(seen.clone());
|
||||
|
||||
for typekey in &already_imported_types {
|
||||
if 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 typedef = imported_mod_typedefs
|
||||
dbg!(&typekey);
|
||||
let mut typedef = imported_mod_typedefs
|
||||
.iter()
|
||||
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
importer_module.typedefs.push(typedef.clone());
|
||||
}
|
||||
if extern_types.contains(&typekey) {
|
||||
typedef = TypeDefinition {
|
||||
importer: Some(importer_module.module_id),
|
||||
..typedef
|
||||
};
|
||||
}
|
||||
|
||||
importer_module.functions.push(FunctionDefinition {
|
||||
name: func_name,
|
||||
is_pub: false,
|
||||
is_imported: false,
|
||||
return_type,
|
||||
parameters: param_tys,
|
||||
kind: super::FunctionDefinitionKind::Extern(true),
|
||||
});
|
||||
importer_module.typedefs.push(typedef);
|
||||
}
|
||||
dbg!(&importer_module.typedefs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -347,3 +310,48 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
typedef: &TypeDefinition,
|
||||
mut seen: HashSet<CustomTypeKey>,
|
||||
mod_id: SourceModuleId,
|
||||
) -> Vec<CustomTypeKey> {
|
||||
match &typedef.kind {
|
||||
crate::mir::TypeDefinitionKind::Struct(struct_type) => {
|
||||
let typenames = struct_type
|
||||
.0
|
||||
.iter()
|
||||
.filter(|t| matches!(t.1, TypeKind::CustomType(..)))
|
||||
.map(|t| match &t.1 {
|
||||
TypeKind::CustomType(CustomTypeKey(t, _)) => t,
|
||||
_ => panic!(),
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for typename in typenames {
|
||||
if seen.contains(&CustomTypeKey(typename.clone(), mod_id)) {
|
||||
continue;
|
||||
}
|
||||
let inner = find_inner_types(typedef, seen.clone(), mod_id);
|
||||
seen.insert(CustomTypeKey(typename, mod_id));
|
||||
seen.extend(inner);
|
||||
}
|
||||
|
||||
seen.into_iter().collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -354,6 +354,7 @@ pub struct TypeDefinition {
|
||||
pub kind: TypeDefinitionKind,
|
||||
pub meta: Metadata,
|
||||
pub source_module: SourceModuleId,
|
||||
pub importer: Option<SourceModuleId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -34,12 +34,7 @@ impl<'t> Pass for TypeCheck<'t> {
|
||||
fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) -> PassResult {
|
||||
let mut defmap = HashMap::new();
|
||||
for typedef in &module.typedefs {
|
||||
let TypeDefinition {
|
||||
name,
|
||||
kind,
|
||||
meta,
|
||||
source_module: _,
|
||||
} = &typedef;
|
||||
let TypeDefinition { name, kind, meta, .. } = &typedef;
|
||||
|
||||
match kind {
|
||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
||||
@ -217,8 +212,6 @@ impl Block {
|
||||
variable_reference.2,
|
||||
);
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user