Compare commits

..

No commits in common. "12e2851a8bfd3c2ce959a14db11ed255e393d1a1" and "0b3ee3bf929563e673382e0d38c72022711be128" have entirely different histories.

27 changed files with 1349 additions and 1971 deletions

View File

@ -1 +0,0 @@
max_width = 120

View File

@ -47,13 +47,13 @@ Currently missing big features (TODOs) are:
- ~~Intrinsic functions~~ (DONE) - ~~Intrinsic functions~~ (DONE)
- ~~Ability to specify types in literals and variable definitions~~ (DONE) - ~~Ability to specify types in literals and variable definitions~~ (DONE)
- ~~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)
Big features that I want later but are not necessary: Big features that I want later but are not necessary:
- Associated functions
- ~~User-defined binary operations~~ (DONE) - ~~User-defined binary operations~~ (DONE)
- ~~Asymmetric binary operations (e.g. string + u32)~~ (DONE) - ~~Asymmetric binary operations (e.g. string + u32)~~ (DONE)
- Error handling - Error handling

View File

@ -1,6 +0,0 @@
pub fn abs(f: f32) -> f32 {
if f < 0.0 {
return f * (0.0 - 1.0);
}
return f;
}

View File

@ -6,4 +6,4 @@ fn main() -> u32 {
let other = 0o17; let other = 0o17;
return value * other + 7 * -value; return value * other + 7 * -value;
} }

View File

@ -13,6 +13,5 @@ fn main() -> u32 {
value.second = 17; value.second = 17;
return value.second; return value.second;
} }

469
foo.reid
View File

@ -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);
}

View File

@ -38,7 +38,7 @@ pub fn new_string() -> String {
} }
pub fn from_str(str: *char) -> String { pub fn from_str(str: *char) -> String {
let length = str_length(str) as u64; let length = str_length(str);
let mut new = new_string(); let mut new = new_string();
let static = String { let static = String {
inner: str, inner: str,

View File

@ -298,7 +298,9 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
'\"' | '\'' => { '\"' | '\'' => {
let mut value = String::new(); let mut value = String::new();
let mut escape_next = false; let mut escape_next = false;
while cursor.first().is_some() && (cursor.first() != Some(*character) || escape_next) { while cursor.first().is_some()
&& (cursor.first() != Some(*character) || escape_next)
{
if cursor.first() == Some('\\') && !escape_next { if cursor.first() == Some('\\') && !escape_next {
cursor.next(); // Consume backslash and always add next character cursor.next(); // Consume backslash and always add next character
escape_next = true; escape_next = true;
@ -364,7 +366,8 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
let mut numerics = DECIMAL_NUMERICS; let mut numerics = DECIMAL_NUMERICS;
if let Some(second) = cursor.second() { if let Some(second) = cursor.second() {
if cursor.first() == Some('x') if cursor.first() == Some('x')
&& HEXADECIMAL_NUMERICS.contains(&second.to_lowercase().next().unwrap_or('.')) && HEXADECIMAL_NUMERICS
.contains(&second.to_lowercase().next().unwrap_or('.'))
{ {
cursor.next(); cursor.next();
value = NumberType::Hexadecimal(String::new()); value = NumberType::Hexadecimal(String::new());
@ -461,7 +464,9 @@ impl AddAssign<char> for NumberType {
fn add_assign(&mut self, rhs: char) { fn add_assign(&mut self, rhs: char) {
*self = match self { *self = match self {
NumberType::Decimal(val) => NumberType::Decimal(val.to_owned() + &rhs.to_string()), NumberType::Decimal(val) => NumberType::Decimal(val.to_owned() + &rhs.to_string()),
NumberType::Hexadecimal(val) => NumberType::Hexadecimal(val.to_owned() + &rhs.to_string()), NumberType::Hexadecimal(val) => {
NumberType::Hexadecimal(val.to_owned() + &rhs.to_string())
}
NumberType::Octal(val) => NumberType::Octal(val.to_owned() + &rhs.to_string()), NumberType::Octal(val) => NumberType::Octal(val.to_owned() + &rhs.to_string()),
NumberType::Binary(val) => NumberType::Binary(val.to_owned() + &rhs.to_string()), NumberType::Binary(val) => NumberType::Binary(val.to_owned() + &rhs.to_string()),
}; };

View File

@ -101,7 +101,6 @@ pub enum ExpressionKind {
pub enum UnaryOperator { pub enum UnaryOperator {
Plus, Plus,
Minus, Minus,
Not,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]

View File

@ -87,7 +87,6 @@ impl Parse for UnaryOperator {
match token { match token {
Token::Plus => Ok(UnaryOperator::Plus), Token::Plus => Ok(UnaryOperator::Plus),
Token::Minus => Ok(UnaryOperator::Minus), Token::Minus => Ok(UnaryOperator::Minus),
Token::Exclamation => Ok(UnaryOperator::Not),
_ => Err(stream.expected_err("unary operator")?), _ => Err(stream.expected_err("unary operator")?),
} }
} else { } else {
@ -175,11 +174,20 @@ impl Parse for PrimaryExpression {
use ExpressionKind as Kind; use ExpressionKind as Kind;
let mut expr = if let Ok(exp) = stream.parse() { let mut expr = if let Ok(exp) = stream.parse() {
Expression(Kind::FunctionCall(Box::new(exp)), stream.get_range().unwrap()) Expression(
Kind::FunctionCall(Box::new(exp)),
stream.get_range().unwrap(),
)
} else if let Ok(block) = stream.parse() { } else if let Ok(block) = stream.parse() {
Expression(Kind::BlockExpr(Box::new(block)), stream.get_range().unwrap()) Expression(
Kind::BlockExpr(Box::new(block)),
stream.get_range().unwrap(),
)
} else if let Some(Token::If) = stream.peek() { } else if let Some(Token::If) = stream.peek() {
Expression(Kind::IfExpr(Box::new(stream.parse()?)), stream.get_range().unwrap()) Expression(
Kind::IfExpr(Box::new(stream.parse()?)),
stream.get_range().unwrap(),
)
} else if let (Some(Token::Et), Some(Token::MutKeyword)) = (stream.peek(), stream.peek2()) { } else if let (Some(Token::Et), Some(Token::MutKeyword)) = (stream.peek(), stream.peek2()) {
stream.next(); // Consume Et stream.next(); // Consume Et
stream.next(); // Consume mut stream.next(); // Consume mut
@ -187,11 +195,15 @@ impl Parse for PrimaryExpression {
return Err(stream.expected_err("identifier")?); return Err(stream.expected_err("identifier")?);
}; };
Expression(Kind::Borrow(name, true), stream.get_range().unwrap()) Expression(Kind::Borrow(name, true), stream.get_range().unwrap())
} else if let (Some(Token::Et), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) { } else if let (Some(Token::Et), Some(Token::Identifier(name))) =
(stream.peek(), stream.peek2())
{
stream.next(); // Consume Et stream.next(); // Consume Et
stream.next(); // Consume identifier stream.next(); // Consume identifier
Expression(Kind::Borrow(name, false), stream.get_range().unwrap()) Expression(Kind::Borrow(name, false), stream.get_range().unwrap())
} else if let (Some(Token::Star), Some(Token::Identifier(name))) = (stream.peek(), stream.peek2()) { } else if let (Some(Token::Star), Some(Token::Identifier(name))) =
(stream.peek(), stream.peek2())
{
stream.next(); // Consume Et stream.next(); // Consume Et
stream.next(); // Consume identifier stream.next(); // Consume identifier
Expression(Kind::Deref(name), stream.get_range().unwrap()) Expression(Kind::Deref(name), stream.get_range().unwrap())
@ -213,35 +225,49 @@ impl Parse for PrimaryExpression {
} }
Token::BinaryValue(v) => { Token::BinaryValue(v) => {
stream.next(); // Consume binary stream.next(); // Consume binary
let value = u128::from_str_radix(&v, 2).expect("Value is not parseable as u128!"); let value =
u128::from_str_radix(&v, 2).expect("Value is not parseable as u128!");
if let Ok(expr) = specific_int_lit(value, &mut stream) { if let Ok(expr) = specific_int_lit(value, &mut stream) {
expr expr
} else { } else {
Expression(Kind::Literal(Literal::Integer(value)), stream.get_range().unwrap()) Expression(
Kind::Literal(Literal::Integer(value)),
stream.get_range().unwrap(),
)
} }
} }
Token::OctalValue(v) => { Token::OctalValue(v) => {
stream.next(); // Consume octal stream.next(); // Consume octal
let value = u128::from_str_radix(&v, 8).expect("Value is not parseable as u128!"); let value =
u128::from_str_radix(&v, 8).expect("Value is not parseable as u128!");
if let Ok(expr) = specific_int_lit(value, &mut stream) { if let Ok(expr) = specific_int_lit(value, &mut stream) {
expr expr
} else { } else {
Expression(Kind::Literal(Literal::Integer(value)), stream.get_range().unwrap()) Expression(
Kind::Literal(Literal::Integer(value)),
stream.get_range().unwrap(),
)
} }
} }
Token::HexadecimalValue(v) => { Token::HexadecimalValue(v) => {
stream.next(); // Consume hexadecimal stream.next(); // Consume hexadecimal
let value = u128::from_str_radix(&v, 16).expect("Value is not parseable as u128!"); let value =
u128::from_str_radix(&v, 16).expect("Value is not parseable as u128!");
if let Ok(expr) = specific_int_lit(value, &mut stream) { if let Ok(expr) = specific_int_lit(value, &mut stream) {
expr expr
} else { } else {
Expression(Kind::Literal(Literal::Integer(value)), stream.get_range().unwrap()) Expression(
Kind::Literal(Literal::Integer(value)),
stream.get_range().unwrap(),
)
} }
} }
Token::DecimalValue(v) => { Token::DecimalValue(v) => {
stream.next(); // Consume decimal stream.next(); // Consume decimal
if let (Some(Token::Dot), Some(Token::DecimalValue(fractional))) = (stream.peek(), stream.peek2()) { if let (Some(Token::Dot), Some(Token::DecimalValue(fractional))) =
(stream.peek(), stream.peek2())
{
stream.next(); // Consume dot stream.next(); // Consume dot
stream.next(); // Consume fractional stream.next(); // Consume fractional
@ -252,20 +278,30 @@ impl Parse for PrimaryExpression {
if let Ok(expr) = specific_float_lit(value, &mut stream) { if let Ok(expr) = specific_float_lit(value, &mut stream) {
expr expr
} else { } else {
Expression(Kind::Literal(Literal::Decimal(value)), stream.get_range().unwrap()) Expression(
Kind::Literal(Literal::Decimal(value)),
stream.get_range().unwrap(),
)
} }
} else { } else {
let value = u128::from_str_radix(&v, 10).expect("Value is not parseable as u128!"); let value =
u128::from_str_radix(&v, 10).expect("Value is not parseable as u128!");
if let Ok(expr) = specific_int_lit(value, &mut stream) { if let Ok(expr) = specific_int_lit(value, &mut stream) {
expr expr
} else { } else {
Expression(Kind::Literal(Literal::Integer(value)), stream.get_range().unwrap()) Expression(
Kind::Literal(Literal::Integer(value)),
stream.get_range().unwrap(),
)
} }
} }
} }
Token::StringLit(v) => { Token::StringLit(v) => {
stream.next(); // Consume stream.next(); // Consume
Expression(Kind::Literal(Literal::String(v.clone())), stream.get_range().unwrap()) Expression(
Kind::Literal(Literal::String(v.clone())),
stream.get_range().unwrap(),
)
} }
Token::CharLit(v) => { Token::CharLit(v) => {
stream.next(); // Consume stream.next(); // Consume
@ -283,11 +319,17 @@ impl Parse for PrimaryExpression {
} }
Token::True => { Token::True => {
stream.next(); // Consume stream.next(); // Consume
Expression(Kind::Literal(Literal::Bool(true)), stream.get_range().unwrap()) Expression(
Kind::Literal(Literal::Bool(true)),
stream.get_range().unwrap(),
)
} }
Token::False => { Token::False => {
stream.next(); // Consume stream.next(); // Consume
Expression(Kind::Literal(Literal::Bool(false)), stream.get_range().unwrap()) Expression(
Kind::Literal(Literal::Bool(false)),
stream.get_range().unwrap(),
)
} }
Token::ParenOpen => { Token::ParenOpen => {
stream.next(); // Consume stream.next(); // Consume
@ -301,14 +343,16 @@ impl Parse for PrimaryExpression {
if let Some(Token::Semi) = stream.peek() { if let Some(Token::Semi) = stream.peek() {
stream.next(); // Consume colon stream.next(); // Consume colon
let Some(Token::DecimalValue(val)) = stream.next() else { let Some(Token::DecimalValue(val)) = stream.next() else {
return Err(stream.expecting_err("decimal value describing array length")?); return Err(stream
.expecting_err("decimal value describing array length")?);
}; };
stream.expect(Token::BracketClose)?; stream.expect(Token::BracketClose)?;
Expression( Expression(
Kind::ArrayShort( Kind::ArrayShort(
Box::new(exp), Box::new(exp),
u64::from_str_radix(&val, 10) u64::from_str_radix(&val, 10).expect(
.expect("Unable to parse array length to 64-bit decimal value"), "Unable to parse array length to 64-bit decimal value",
),
), ),
stream.get_range().unwrap(), stream.get_range().unwrap(),
) )
@ -470,7 +514,11 @@ impl Parse for FunctionCallExpression {
stream.expect(Token::ParenClose)?; stream.expect(Token::ParenClose)?;
Ok(FunctionCallExpression(name, args, stream.get_range().unwrap())) Ok(FunctionCallExpression(
name,
args,
stream.get_range().unwrap(),
))
} else { } else {
Err(stream.expected_err("identifier")?) Err(stream.expected_err("identifier")?)
} }
@ -487,7 +535,12 @@ impl Parse for IfExpression {
} else { } else {
None None
}; };
Ok(IfExpression(cond, then_b, else_b, stream.get_range().unwrap())) Ok(IfExpression(
cond,
then_b,
else_b,
stream.get_range().unwrap(),
))
} }
} }
@ -647,7 +700,11 @@ impl Parse for Block {
statements.push(statement); statements.push(statement);
} }
stream.expect(Token::BraceClose)?; stream.expect(Token::BraceClose)?;
Ok(Block(statements, return_stmt, stream.get_range_prev().unwrap())) Ok(Block(
statements,
return_stmt,
stream.get_range_prev().unwrap(),
))
} }
} }
@ -752,7 +809,9 @@ impl Parse for BlockLevelStatement {
use BlockLevelStatement as Stmt; use BlockLevelStatement as Stmt;
Ok(match stream.peek() { Ok(match stream.peek() {
Some(Token::LetKeyword) => Stmt::Let(stream.parse()?), Some(Token::LetKeyword) => Stmt::Let(stream.parse()?),
Some(Token::ImportKeyword) => Stmt::Import { _i: stream.parse()? }, Some(Token::ImportKeyword) => Stmt::Import {
_i: stream.parse()?,
},
Some(Token::ReturnKeyword) => { Some(Token::ReturnKeyword) => {
stream.next(); stream.next();
let exp = stream.parse().ok(); let exp = stream.parse().ok();
@ -865,7 +924,9 @@ impl Parse for TopLevelStatement {
stream.expect(Token::Semi)?; stream.expect(Token::Semi)?;
extern_fn extern_fn
} }
Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?), Some(Token::FnKeyword) | Some(Token::PubKeyword) => {
Stmt::FunctionDefinition(stream.parse()?)
}
Some(Token::Struct) => { Some(Token::Struct) => {
let StructDefinition(name, fields, range) = stream.parse::<StructDefinition>()?; let StructDefinition(name, fields, range) = stream.parse::<StructDefinition>()?;
Stmt::TypeDefinition(TypeDefinition { Stmt::TypeDefinition(TypeDefinition {

View File

@ -3,8 +3,8 @@ use std::path::PathBuf;
use crate::{ use crate::{
ast::{self}, ast::{self},
mir::{ mir::{
self, CustomTypeKey, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind, StructField, self, CustomTypeKey, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind,
StructType, WhileStatement, StructField, StructType, WhileStatement,
}, },
}; };
@ -162,7 +162,9 @@ impl ast::Block {
*range, *range,
), ),
ast::BlockLevelStatement::Import { _i } => todo!(), ast::BlockLevelStatement::Import { _i } => todo!(),
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process(module_id)), e.1), ast::BlockLevelStatement::Expression(e) => {
(StmtKind::Expression(e.process(module_id)), e.1)
}
ast::BlockLevelStatement::Return(_, e) => { ast::BlockLevelStatement::Return(_, e) => {
if let Some(e) = e { if let Some(e) = e {
(StmtKind::Expression(e.process(module_id)), e.1) (StmtKind::Expression(e.process(module_id)), e.1)
@ -195,10 +197,11 @@ impl ast::Block {
counter_range.as_meta(module_id), counter_range.as_meta(module_id),
)), )),
Box::new(mir::Expression( Box::new(mir::Expression(
mir::ExprKind::Literal(mir::Literal::Vague(mir::VagueLiteral::Number(1))), mir::ExprKind::Literal(mir::Literal::Vague(
mir::VagueLiteral::Number(1),
)),
counter_range.as_meta(module_id), counter_range.as_meta(module_id),
)), )),
mir::TypeKind::Vague(mir::VagueType::Unknown),
), ),
counter_range.as_meta(module_id), counter_range.as_meta(module_id),
), ),
@ -217,7 +220,6 @@ impl ast::Block {
counter_range.as_meta(module_id), counter_range.as_meta(module_id),
)), )),
Box::new(end.process(module_id)), Box::new(end.process(module_id)),
mir::TypeKind::Vague(mir::VagueType::Unknown),
), ),
counter_range.as_meta(module_id), counter_range.as_meta(module_id),
), ),
@ -290,15 +292,22 @@ impl ast::Expression {
binary_operator.mir(), binary_operator.mir(),
Box::new(lhs.process(module_id)), Box::new(lhs.process(module_id)),
Box::new(rhs.process(module_id)), Box::new(rhs.process(module_id)),
mir::TypeKind::Vague(mir::VagueType::Unknown),
), ),
ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall { ast::ExpressionKind::FunctionCall(fn_call_expr) => {
name: fn_call_expr.0.clone(), mir::ExprKind::FunctionCall(mir::FunctionCall {
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), name: fn_call_expr.0.clone(),
parameters: fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(), return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
meta: fn_call_expr.2.as_meta(module_id), parameters: fn_call_expr
}), .1
ast::ExpressionKind::BlockExpr(block) => mir::ExprKind::Block(block.into_mir(module_id)), .iter()
.map(|e| e.process(module_id))
.collect(),
meta: fn_call_expr.2.as_meta(module_id),
})
}
ast::ExpressionKind::BlockExpr(block) => {
mir::ExprKind::Block(block.into_mir(module_id))
}
ast::ExpressionKind::IfExpr(if_expression) => { ast::ExpressionKind::IfExpr(if_expression) => {
let cond = if_expression.0.process(module_id); let cond = if_expression.0.process(module_id);
let then_block = if_expression.1.process(module_id); let then_block = if_expression.1.process(module_id);
@ -355,7 +364,6 @@ impl ast::Expression {
expr.1.as_meta(module_id), expr.1.as_meta(module_id),
)), )),
Box::new(expr.process(module_id)), Box::new(expr.process(module_id)),
mir::TypeKind::Vague(mir::VagueType::Unknown),
), ),
ast::UnaryOperator::Minus => mir::ExprKind::BinOp( ast::UnaryOperator::Minus => mir::ExprKind::BinOp(
mir::BinaryOperator::Minus, mir::BinaryOperator::Minus,
@ -364,16 +372,6 @@ impl ast::Expression {
expr.1.as_meta(module_id), expr.1.as_meta(module_id),
)), )),
Box::new(expr.process(module_id)), Box::new(expr.process(module_id)),
mir::TypeKind::Vague(mir::VagueType::Unknown),
),
ast::UnaryOperator::Not => mir::ExprKind::BinOp(
mir::BinaryOperator::Cmp(mir::CmpOperator::EQ),
Box::new(expr.process(module_id)),
Box::new(mir::Expression(
mir::ExprKind::Literal(mir::Literal::Bool(false)),
expr.1.as_meta(module_id),
)),
mir::TypeKind::Bool,
), ),
}, },
ast::ExpressionKind::CastTo(expression, ty) => mir::ExprKind::CastTo( ast::ExpressionKind::CastTo(expression, ty) => mir::ExprKind::CastTo(
@ -459,11 +457,15 @@ impl ast::TypeKind {
ast::TypeKind::Array(type_kind, length) => { ast::TypeKind::Array(type_kind, length) => {
mir::TypeKind::Array(Box::new(type_kind.clone().into_mir(source_mod)), *length) mir::TypeKind::Array(Box::new(type_kind.clone().into_mir(source_mod)), *length)
} }
ast::TypeKind::Custom(name) => mir::TypeKind::CustomType(CustomTypeKey(name.clone(), source_mod)), ast::TypeKind::Custom(name) => {
mir::TypeKind::CustomType(CustomTypeKey(name.clone(), source_mod))
}
ast::TypeKind::Borrow(type_kind, mutable) => { ast::TypeKind::Borrow(type_kind, mutable) => {
mir::TypeKind::Borrow(Box::new(type_kind.clone().into_mir(source_mod)), *mutable) mir::TypeKind::Borrow(Box::new(type_kind.clone().into_mir(source_mod)), *mutable)
} }
ast::TypeKind::Ptr(type_kind) => mir::TypeKind::UserPtr(Box::new(type_kind.clone().into_mir(source_mod))), ast::TypeKind::Ptr(type_kind) => {
mir::TypeKind::UserPtr(Box::new(type_kind.clone().into_mir(source_mod)))
}
ast::TypeKind::F16 => mir::TypeKind::F16, ast::TypeKind::F16 => mir::TypeKind::F16,
ast::TypeKind::F32B => mir::TypeKind::F32B, ast::TypeKind::F32B => mir::TypeKind::F32B,
ast::TypeKind::F32 => mir::TypeKind::F32, ast::TypeKind::F32 => mir::TypeKind::F32,

View File

@ -6,7 +6,8 @@ use reid_lib::{
}; };
use crate::mir::{ use crate::mir::{
self, CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, SourceModuleId, TypeKind, WhileStatement, self, CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, SourceModuleId,
TypeKind, WhileStatement,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -73,7 +74,9 @@ impl mir::FunctionDefinitionKind {
mir::FunctionDefinitionKind::Intrinsic(_) => {} mir::FunctionDefinitionKind::Intrinsic(_) => {}
} }
Allocator { allocations: allocated } Allocator {
allocations: allocated,
}
} }
} }
@ -123,7 +126,9 @@ impl mir::Statement {
crate::mir::StmtKind::Expression(expression) => { crate::mir::StmtKind::Expression(expression) => {
allocated.extend(expression.allocate(scope)); allocated.extend(expression.allocate(scope));
} }
crate::mir::StmtKind::While(WhileStatement { condition, block, .. }) => { crate::mir::StmtKind::While(WhileStatement {
condition, block, ..
}) => {
allocated.extend(condition.allocate(scope)); allocated.extend(condition.allocate(scope));
allocated.extend(block.allocate(scope)); allocated.extend(block.allocate(scope));
} }
@ -157,7 +162,7 @@ impl mir::Expression {
} }
} }
crate::mir::ExprKind::Literal(_) => {} crate::mir::ExprKind::Literal(_) => {}
crate::mir::ExprKind::BinOp(_, lhs, rhs, _) => { crate::mir::ExprKind::BinOp(_, lhs, rhs) => {
allocated.extend(lhs.allocate(scope)); allocated.extend(lhs.allocate(scope));
allocated.extend(rhs.allocate(scope)); allocated.extend(rhs.allocate(scope));
} }

View File

@ -1,286 +1,78 @@
use std::marker::PhantomData; use reid_lib::{builder::InstructionValue, Instr};
use reid_lib::{builder::InstructionValue, CmpPredicate, Instr};
use crate::{ use crate::{
codegen::{ErrorKind, StackValueKind}, codegen::{ErrorKind, StackValueKind},
mir::{BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, TypeKind}, mir::{BinopDefinition, FunctionDefinition, TypeKind},
}; };
use super::scope::{Scope, StackValue}; use super::scope::{Scope, StackValue};
const INTEGERS: [TypeKind; 10] = [
TypeKind::U8,
TypeKind::U16,
TypeKind::U32,
TypeKind::U64,
TypeKind::U128,
TypeKind::I8,
TypeKind::I16,
TypeKind::I32,
TypeKind::I64,
TypeKind::I128,
];
const FLOATS: [TypeKind; 7] = [
TypeKind::F16,
TypeKind::F32,
TypeKind::F32B,
TypeKind::F64,
TypeKind::F80,
TypeKind::F128,
TypeKind::F128PPC,
];
pub fn form_intrinsics() -> Vec<FunctionDefinition> { pub fn form_intrinsics() -> Vec<FunctionDefinition> {
let intrinsics = Vec::new(); let intrinsics = Vec::new();
intrinsics intrinsics
} }
fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{
BinopDefinition {
lhs: ("lhs".to_owned(), ty.clone()),
op,
rhs: ("rhs".to_owned(), ty.clone()),
return_type: ty.clone(),
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
meta: Default::default(),
}
}
fn boolean_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{
BinopDefinition {
lhs: ("lhs".to_owned(), ty.clone()),
op,
rhs: ("rhs".to_owned(), ty.clone()),
return_type: TypeKind::Bool,
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))),
meta: Default::default(),
}
}
pub fn form_intrinsic_binops() -> Vec<BinopDefinition> { pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
let mut intrinsics = Vec::new(); let mut intrinsics = Vec::new();
use BinaryOperator::*;
for ty in INTEGERS {
intrinsics.push(simple_binop_def(Add, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::Add(lhs, rhs)).unwrap()
}));
intrinsics.push(simple_binop_def(Mult, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::Mul(lhs, rhs)).unwrap()
}));
intrinsics.push(simple_binop_def(Minus, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::Sub(lhs, rhs)).unwrap()
}));
if ty.signed() {
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::SDiv(lhs, rhs)).unwrap()
}));
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
let div = scope.block.build(Instr::SDiv(lhs, rhs)).unwrap();
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
}));
} else {
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::UDiv(lhs, rhs)).unwrap()
}));
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
let div = scope.block.build(Instr::UDiv(lhs, rhs)).unwrap();
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
}));
}
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::ICmp(CmpPredicate::GT, lhs, rhs)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GE), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::ICmp(CmpPredicate::GE, lhs, rhs)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LT), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::ICmp(CmpPredicate::LT, lhs, rhs)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LE), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::ICmp(CmpPredicate::LE, lhs, rhs)).unwrap()
}));
}
for ty in INTEGERS.iter().chain(&[TypeKind::Bool, TypeKind::Char]) {
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::ICmp(CmpPredicate::EQ, lhs, rhs)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::ICmp(CmpPredicate::NE, lhs, rhs)).unwrap()
}));
}
for ty in FLOATS {
intrinsics.push(simple_binop_def(BinaryOperator::Add, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FAdd(lhs, rhs)).unwrap()
}));
intrinsics.push(simple_binop_def(BinaryOperator::Mult, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FMul(lhs, rhs)).unwrap()
}));
intrinsics.push(simple_binop_def(BinaryOperator::Minus, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FSub(lhs, rhs)).unwrap()
}));
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FDiv(lhs, rhs)).unwrap()
}));
intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap();
let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
scope.block.build(Instr::Sub(lhs, mul)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::NE), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FCmp(CmpPredicate::NE, lhs, rhs)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FCmp(CmpPredicate::GT, lhs, rhs)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GE), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FCmp(CmpPredicate::GE, lhs, rhs)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LT), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FCmp(CmpPredicate::LT, lhs, rhs)).unwrap()
}));
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::LE), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FCmp(CmpPredicate::LE, lhs, rhs)).unwrap()
}));
}
intrinsics.push(boolean_binop_def(And, &TypeKind::Bool, |scope, lhs, rhs| {
scope.block.build(Instr::And(lhs, rhs)).unwrap()
}));
intrinsics intrinsics
} }
pub trait IntrinsicFunction: std::fmt::Debug { pub trait IntrinsicFunction: std::fmt::Debug {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[&StackValue]) -> Result<StackValue, ErrorKind>; fn codegen<'ctx, 'a>(
&self,
scope: &mut Scope<'ctx, 'a>,
params: &[InstructionValue],
) -> Result<StackValue, ErrorKind>;
} }
#[derive(Clone)] #[derive(Debug, Clone)]
pub struct IntrinsicSimpleInstr<T>(T) pub struct IntrinsicIAdd(TypeKind);
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
impl<T> std::fmt::Debug for IntrinsicSimpleInstr<T> impl IntrinsicFunction for IntrinsicIAdd {
where fn codegen<'ctx, 'a>(
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, &self,
{ scope: &mut Scope<'ctx, 'a>,
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { params: &[InstructionValue],
f.debug_tuple("IntrinsicSimpleInstr").finish() ) -> Result<StackValue, ErrorKind> {
}
}
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[&StackValue]) -> Result<StackValue, ErrorKind> {
let lhs = params.get(0).unwrap(); let lhs = params.get(0).unwrap();
let rhs = params.get(1).unwrap(); let rhs = params.get(1).unwrap();
let instr = self.clone().0(scope, lhs.instr(), rhs.instr()); let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
Ok(StackValue(StackValueKind::Literal(instr), lhs.1.clone())) Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
} }
} }
#[derive(Clone)] #[derive(Debug, Clone)]
pub struct IntrinsicBooleanInstr<T>(T) pub struct IntrinsicUDiv(TypeKind);
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
impl<T> std::fmt::Debug for IntrinsicBooleanInstr<T> impl IntrinsicFunction for IntrinsicUDiv {
where fn codegen<'ctx, 'a>(
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, &self,
{ scope: &mut Scope<'ctx, 'a>,
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { params: &[InstructionValue],
f.debug_tuple("IntrinsicBooleanInstr").finish() ) -> Result<StackValue, ErrorKind> {
}
}
impl<T: Clone> IntrinsicFunction for IntrinsicBooleanInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[&StackValue]) -> Result<StackValue, ErrorKind> {
let lhs = params.get(0).unwrap(); let lhs = params.get(0).unwrap();
let rhs = params.get(1).unwrap(); let rhs = params.get(1).unwrap();
let instr = self.clone().0(scope, lhs.instr(), rhs.instr()); let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
Ok(StackValue(StackValueKind::Literal(instr), TypeKind::Bool)) Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
} }
} }
// impl IntrinsicFunction for IntrinsicIAdd { #[derive(Debug, Clone)]
// fn codegen<'ctx, 'a>( pub struct IntrinsicUMod(TypeKind);
// &self,
// scope: &mut Scope<'ctx, 'a>,
// params: &[InstructionValue],
// ) -> Result<StackValue, ErrorKind> {
// let lhs = params.get(0).unwrap();
// let rhs = params.get(1).unwrap();
// let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap();
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
// }
// }
// #[derive(Debug, Clone)] impl IntrinsicFunction for IntrinsicUMod {
// pub struct IntrinsicIAdd(TypeKind); fn codegen<'ctx, 'a>(
&self,
// impl IntrinsicFunction for IntrinsicIAdd { scope: &mut Scope<'ctx, 'a>,
// fn codegen<'ctx, 'a>( params: &[InstructionValue],
// &self, ) -> Result<StackValue, ErrorKind> {
// scope: &mut Scope<'ctx, 'a>, let lhs = params.get(0).unwrap();
// params: &[InstructionValue], let rhs = params.get(1).unwrap();
// ) -> Result<StackValue, ErrorKind> { let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
// let lhs = params.get(0).unwrap(); let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap();
// let rhs = params.get(1).unwrap(); let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap();
// let add = scope.block.build(Instr::Add(*lhs, *rhs)).unwrap(); Ok(StackValue(StackValueKind::Literal(sub), self.0.clone()))
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone())) }
// } }
// }
// #[derive(Debug, Clone)]
// pub struct IntrinsicUDiv(TypeKind);
// impl IntrinsicFunction for IntrinsicUDiv {
// fn codegen<'ctx, 'a>(
// &self,
// scope: &mut Scope<'ctx, 'a>,
// params: &[InstructionValue],
// ) -> Result<StackValue, ErrorKind> {
// let lhs = params.get(0).unwrap();
// let rhs = params.get(1).unwrap();
// let add = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
// Ok(StackValue(StackValueKind::Literal(add), self.0.clone()))
// }
// }
// #[derive(Debug, Clone)]
// pub struct IntrinsicUMod(TypeKind);
// impl IntrinsicFunction for IntrinsicUMod {
// fn codegen<'ctx, 'a>(
// &self,
// scope: &mut Scope<'ctx, 'a>,
// params: &[InstructionValue],
// ) -> Result<StackValue, ErrorKind> {
// let lhs = params.get(0).unwrap();
// let rhs = params.get(1).unwrap();
// let div = scope.block.build(Instr::UDiv(*lhs, *rhs)).unwrap();
// let mul = scope.block.build(Instr::Mul(*rhs, div)).unwrap();
// let sub = scope.block.build(Instr::Sub(*lhs, mul)).unwrap();
// Ok(StackValue(StackValueKind::Literal(sub), self.0.clone()))
// }
// }

View File

@ -5,18 +5,20 @@ use intrinsics::*;
use reid_lib::{ use reid_lib::{
compile::CompiledModule, compile::CompiledModule,
debug_information::{ debug_information::{
DebugFileData, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind, DebugSubprogramData, DebugFileData, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind,
DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DwarfFlags, InstructionDebugRecordData, DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData,
DwarfFlags, InstructionDebugRecordData,
}, },
CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct, CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module,
TerminatorKind as Term, Type, NamedStruct, TerminatorKind as Term, Type,
}; };
use scope::*; use scope::*;
use crate::{ use crate::{
mir::{ mir::{
self, implement::TypeCategory, pass::ScopeBinopKey, CustomTypeKey, FunctionDefinitionKind, NamedVariableRef, self, implement::TypeCategory, pass::ScopeBinopKey, CustomTypeKey, FunctionDefinitionKind,
SourceModuleId, StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement, NamedVariableRef, SourceModuleId, StructField, StructType, TypeDefinitionKind, TypeKind,
WhileStatement,
}, },
util::try_all, util::try_all,
}; };
@ -81,7 +83,9 @@ struct State {
impl State { impl State {
/// Sets should load, returning a new state /// Sets should load, returning a new state
fn load(self, should: bool) -> State { fn load(self, should: bool) -> State {
State { should_load: should } State {
should_load: should,
}
} }
} }
@ -231,7 +235,10 @@ impl mir::Module {
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,
..Default::default() ..Default::default()
@ -280,7 +287,9 @@ impl mir::Module {
&binop.return_type, &binop.return_type,
&ir_function, &ir_function,
match &binop.fn_kind { match &binop.fn_kind {
FunctionDefinitionKind::Local(_, meta) => meta.into_debug(tokens, compile_unit), FunctionDefinitionKind::Local(_, meta) => {
meta.into_debug(tokens, compile_unit)
}
FunctionDefinitionKind::Extern(_) => None, FunctionDefinitionKind::Extern(_) => None,
FunctionDefinitionKind::Intrinsic(_) => None, FunctionDefinitionKind::Intrinsic(_) => None,
}, },
@ -343,7 +352,9 @@ impl mir::Module {
&mir_function.return_type, &mir_function.return_type,
&function, &function,
match &mir_function.kind { match &mir_function.kind {
FunctionDefinitionKind::Local(..) => mir_function.signature().into_debug(tokens, compile_unit), FunctionDefinitionKind::Local(..) => {
mir_function.signature().into_debug(tokens, compile_unit)
}
FunctionDefinitionKind::Extern(_) => None, FunctionDefinitionKind::Extern(_) => None,
FunctionDefinitionKind::Intrinsic(_) => None, FunctionDefinitionKind::Intrinsic(_) => None,
}, },
@ -375,10 +386,13 @@ impl FunctionDefinitionKind {
let fn_param_ty = &return_type.get_debug_type(&debug, scope); let fn_param_ty = &return_type.get_debug_type(&debug, scope);
let debug_ty = debug.info.debug_type(DebugTypeData::Subprogram(DebugSubprogramType { let debug_ty =
parameters: vec![*fn_param_ty], debug
flags: DwarfFlags, .info
})); .debug_type(DebugTypeData::Subprogram(DebugSubprogramType {
parameters: vec![*fn_param_ty],
flags: DwarfFlags,
}));
let subprogram = debug.info.subprogram(DebugSubprogramData { let subprogram = debug.info.subprogram(DebugSubprogramData {
name: name.clone(), name: name.clone(),
@ -463,7 +477,9 @@ impl FunctionDefinitionKind {
} }
if let Some(debug) = &scope.debug { if let Some(debug) = &scope.debug {
if let Some(location) = &block.return_meta().into_debug(scope.tokens, debug.scope) { if let Some(location) =
&block.return_meta().into_debug(scope.tokens, debug.scope)
{
let location = debug.info.location(&debug.scope, *location); let location = debug.info.location(&debug.scope, *location);
scope.block.set_terminator_location(location).unwrap(); scope.block.set_terminator_location(location).unwrap();
} }
@ -520,7 +536,11 @@ impl mir::Block {
} }
impl mir::Statement { impl mir::Statement {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> { fn codegen<'ctx, 'a>(
&self,
scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> Result<Option<StackValue>, ErrorKind> {
let location = scope.debug.clone().map(|d| { let location = scope.debug.clone().map(|d| {
let location = self.1.into_debug(scope.tokens, d.scope).unwrap(); let location = self.1.into_debug(scope.tokens, d.scope).unwrap();
d.info.location(&d.scope, location) d.info.location(&d.scope, location)
@ -537,7 +557,10 @@ impl mir::Statement {
let store = scope let store = scope
.block .block
.build_named(format!("{}.store", name), Instr::Store(alloca, value.instr())) .build_named(
format!("{}.store", name),
Instr::Store(alloca, value.instr()),
)
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location); .maybe_location(&mut scope.block, location);
@ -609,12 +632,17 @@ impl mir::Statement {
} }
mir::StmtKind::Import(_) => todo!(), mir::StmtKind::Import(_) => todo!(),
mir::StmtKind::Expression(expression) => expression.codegen(scope, state), mir::StmtKind::Expression(expression) => expression.codegen(scope, state),
mir::StmtKind::While(WhileStatement { condition, block, .. }) => { mir::StmtKind::While(WhileStatement {
condition, block, ..
}) => {
let condition_block = scope.function.block("while.cond"); let condition_block = scope.function.block("while.cond");
let condition_true_block = scope.function.block("while.body"); let condition_true_block = scope.function.block("while.body");
let condition_failed_block = scope.function.block("while.end"); let condition_failed_block = scope.function.block("while.end");
scope.block.terminate(Term::Br(condition_block.value())).unwrap(); scope
.block
.terminate(Term::Br(condition_block.value()))
.unwrap();
let mut condition_scope = scope.with_block(condition_block); let mut condition_scope = scope.with_block(condition_block);
let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap(); let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap();
let true_instr = condition_scope let true_instr = condition_scope
@ -623,7 +651,11 @@ impl mir::Statement {
.unwrap(); .unwrap();
let check = condition_scope let check = condition_scope
.block .block
.build(Instr::ICmp(CmpPredicate::EQ, condition_res.instr(), true_instr)) .build(Instr::ICmp(
CmpPredicate::EQ,
condition_res.instr(),
true_instr,
))
.unwrap(); .unwrap();
condition_scope condition_scope
@ -653,13 +685,16 @@ impl mir::Statement {
} }
impl mir::Expression { impl mir::Expression {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> { fn codegen<'ctx, 'a>(
&self,
scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> Result<Option<StackValue>, ErrorKind> {
let location = if let Some(debug) = &scope.debug { let location = if let Some(debug) = &scope.debug {
Some( Some(debug.info.location(
debug &debug.scope,
.info self.1.into_debug(scope.tokens, debug.scope).unwrap(),
.location(&debug.scope, self.1.into_debug(scope.tokens, debug.scope).unwrap()), ))
)
} else { } else {
None None
}; };
@ -680,7 +715,10 @@ impl mir::Expression {
.block .block
.build_named( .build_named(
format!("{}", varref.1), format!("{}", varref.1),
Instr::Load(v.0.instr(), inner.get_type(scope.type_values)), Instr::Load(
v.0.instr(),
inner.get_type(scope.type_values),
),
) )
.unwrap(), .unwrap(),
), ),
@ -698,9 +736,13 @@ impl mir::Expression {
StackValueKind::Literal(lit.as_const(&mut scope.block)), StackValueKind::Literal(lit.as_const(&mut scope.block)),
lit.as_type(), lit.as_type(),
)), )),
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp, return_ty) => { mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
let lhs_val = lhs_exp.codegen(scope, state)?.expect("lhs has no return value"); let lhs_val = lhs_exp
let rhs_val = rhs_exp.codegen(scope, state)?.expect("rhs has no return value"); .codegen(scope, state)?
.expect("lhs has no return value");
let rhs_val = rhs_exp
.codegen(scope, state)?
.expect("rhs has no return value");
let lhs = lhs_val.instr(); let lhs = lhs_val.instr();
let rhs = rhs_val.instr(); let rhs = rhs_val.instr();
@ -713,8 +755,15 @@ impl mir::Expression {
let a = operation.codegen(&lhs_val, &rhs_val, scope)?; let a = operation.codegen(&lhs_val, &rhs_val, scope)?;
Some(a) Some(a)
} else { } else {
let lhs_type = lhs_exp.return_type(&Default::default(), scope.module_id).unwrap().1; let lhs_type = lhs_exp
let instr = match (binop, lhs_type.signed(), lhs_type.category() == TypeCategory::Real) { .return_type(&Default::default(), scope.module_id)
.unwrap()
.1;
let instr = match (
binop,
lhs_type.signed(),
lhs_type.category() == TypeCategory::Real,
) {
(mir::BinaryOperator::Add, _, false) => Instr::Add(lhs, rhs), (mir::BinaryOperator::Add, _, false) => Instr::Add(lhs, rhs),
(mir::BinaryOperator::Add, _, true) => Instr::FAdd(lhs, rhs), (mir::BinaryOperator::Add, _, true) => Instr::FAdd(lhs, rhs),
(mir::BinaryOperator::Minus, _, false) => Instr::Sub(lhs, rhs), (mir::BinaryOperator::Minus, _, false) => Instr::Sub(lhs, rhs),
@ -722,8 +771,12 @@ impl mir::Expression {
(mir::BinaryOperator::Mult, _, false) => Instr::Mul(lhs, rhs), (mir::BinaryOperator::Mult, _, false) => Instr::Mul(lhs, rhs),
(mir::BinaryOperator::Mult, _, true) => Instr::FMul(lhs, rhs), (mir::BinaryOperator::Mult, _, true) => Instr::FMul(lhs, rhs),
(mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs), (mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs),
(mir::BinaryOperator::Cmp(i), _, false) => Instr::ICmp(i.predicate(), lhs, rhs), (mir::BinaryOperator::Cmp(i), _, false) => {
(mir::BinaryOperator::Cmp(i), _, true) => Instr::FCmp(i.predicate(), lhs, rhs), Instr::ICmp(i.predicate(), lhs, rhs)
}
(mir::BinaryOperator::Cmp(i), _, true) => {
Instr::FCmp(i.predicate(), lhs, rhs)
}
(mir::BinaryOperator::Div, false, false) => Instr::UDiv(lhs, rhs), (mir::BinaryOperator::Div, false, false) => Instr::UDiv(lhs, rhs),
(mir::BinaryOperator::Div, true, false) => Instr::SDiv(lhs, rhs), (mir::BinaryOperator::Div, true, false) => Instr::SDiv(lhs, rhs),
(mir::BinaryOperator::Div, _, true) => Instr::FDiv(lhs, rhs), (mir::BinaryOperator::Div, _, true) => Instr::FDiv(lhs, rhs),
@ -775,12 +828,15 @@ impl mir::Expression {
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location), .maybe_location(&mut scope.block, location),
), ),
return_ty.clone(), lhs_type,
)) ))
} }
} }
mir::ExprKind::FunctionCall(call) => { mir::ExprKind::FunctionCall(call) => {
let ret_type_kind = call.return_type.known().expect("function return type unknown"); let ret_type_kind = call
.return_type
.known()
.expect("function return type unknown");
let ret_type = ret_type_kind.get_type(scope.type_values); let ret_type = ret_type_kind.get_type(scope.type_values);
@ -796,11 +852,17 @@ impl mir::Expression {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let param_instrs = params.iter().map(|e| e.instr()).collect(); let param_instrs = params.iter().map(|e| e.instr()).collect();
let callee = scope.functions.get(&call.name).expect("function not found!"); let callee = scope
.functions
.get(&call.name)
.expect("function not found!");
let val = scope let val = scope
.block .block
.build_named(call.name.clone(), Instr::FunctionCall(callee.value(), param_instrs)) .build_named(
call.name.clone(),
Instr::FunctionCall(callee.value(), param_instrs),
)
.unwrap(); .unwrap();
if let Some(debug) = &scope.debug { if let Some(debug) = &scope.debug {
@ -877,7 +939,10 @@ impl mir::Expression {
let (ptr, contained_ty) = if let TypeKind::UserPtr(further_inner) = *inner.clone() { let (ptr, contained_ty) = if let TypeKind::UserPtr(further_inner) = *inner.clone() {
let loaded = scope let loaded = scope
.block .block
.build_named("load", Instr::Load(kind.instr(), inner.get_type(scope.type_values))) .build_named(
"load",
Instr::Load(kind.instr(), inner.get_type(scope.type_values)),
)
.unwrap(); .unwrap();
( (
scope scope
@ -895,7 +960,10 @@ impl mir::Expression {
( (
scope scope
.block .block
.build_named(format!("array.gep"), Instr::GetElemPtr(kind.instr(), vec![idx])) .build_named(
format!("array.gep"),
Instr::GetElemPtr(kind.instr(), vec![idx]),
)
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location), .maybe_location(&mut scope.block, location),
val_t.clone(), val_t.clone(),
@ -912,7 +980,10 @@ impl mir::Expression {
( (
scope scope
.block .block
.build_named(format!("array.gep"), Instr::GetElemPtr(kind.instr(), vec![first, idx])) .build_named(
format!("array.gep"),
Instr::GetElemPtr(kind.instr(), vec![first, idx]),
)
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location), .maybe_location(&mut scope.block, location),
val_t.clone(), val_t.clone(),
@ -924,7 +995,10 @@ impl mir::Expression {
kind.derive( kind.derive(
scope scope
.block .block
.build_named("array.load", Instr::Load(ptr, contained_ty.get_type(scope.type_values))) .build_named(
"array.load",
Instr::Load(ptr, contained_ty.get_type(scope.type_values)),
)
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location), .maybe_location(&mut scope.block, location),
), ),
@ -938,14 +1012,21 @@ impl mir::Expression {
} }
} }
mir::ExprKind::Array(expressions) => { mir::ExprKind::Array(expressions) => {
let stack_value_list: Vec<_> = let stack_value_list: Vec<_> = try_all(
try_all(expressions.iter().map(|e| e.codegen(scope, state)).collect::<Vec<_>>()) expressions
.map_err(|e| e.first().cloned().unwrap())? .iter()
.into_iter() .map(|e| e.codegen(scope, state))
.map(|v| v.unwrap()) .collect::<Vec<_>>(),
.collect(); )
.map_err(|e| e.first().cloned().unwrap())?
.into_iter()
.map(|v| v.unwrap())
.collect();
let instr_list = stack_value_list.iter().map(|s| s.instr()).collect::<Vec<_>>(); let instr_list = stack_value_list
.iter()
.map(|s| s.instr())
.collect::<Vec<_>>();
let elem_ty_kind = stack_value_list let elem_ty_kind = stack_value_list
.iter() .iter()
@ -972,7 +1053,10 @@ impl mir::Expression {
let index_expr = scope let index_expr = scope
.block .block
.build_named(index.to_string(), Instr::Constant(ConstValue::U32(index as u32))) .build_named(
index.to_string(),
Instr::Constant(ConstValue::U32(index as u32)),
)
.unwrap(); .unwrap();
let first = scope let first = scope
.block .block
@ -1010,7 +1094,8 @@ impl mir::Expression {
let TypeKind::CustomType(key) = *inner.clone() else { let TypeKind::CustomType(key) = *inner.clone() else {
panic!("tried accessing non-custom-type"); panic!("tried accessing non-custom-type");
}; };
let TypeDefinitionKind::Struct(struct_ty) = scope.get_typedef(&key).unwrap().kind.clone(); let TypeDefinitionKind::Struct(struct_ty) =
scope.get_typedef(&key).unwrap().kind.clone();
let idx = struct_ty.find_index(field).unwrap(); let idx = struct_ty.find_index(field).unwrap();
let gep_n = format!("{}.{}.gep", key.0, field); let gep_n = format!("{}.{}.gep", key.0, field);
@ -1018,7 +1103,10 @@ impl mir::Expression {
let value = scope let value = scope
.block .block
.build_named(gep_n, Instr::GetStructElemPtr(struct_val.instr(), idx as u32)) .build_named(
gep_n,
Instr::GetStructElemPtr(struct_val.instr(), idx as u32),
)
.unwrap(); .unwrap();
// value.maybe_location(&mut scope.block, location); // value.maybe_location(&mut scope.block, location);
@ -1028,7 +1116,10 @@ impl mir::Expression {
struct_val.0.derive( struct_val.0.derive(
scope scope
.block .block
.build_named(load_n, Instr::Load(value, type_kind.get_type(scope.type_values))) .build_named(
load_n,
Instr::Load(value, type_kind.get_type(scope.type_values)),
)
.unwrap(), .unwrap(),
), ),
struct_ty.get_field_ty(&field).unwrap().clone(), struct_ty.get_field_ty(&field).unwrap().clone(),
@ -1036,38 +1127,32 @@ impl mir::Expression {
} else { } else {
Some(StackValue( Some(StackValue(
struct_val.0.derive(value), struct_val.0.derive(value),
TypeKind::CodegenPtr(Box::new(struct_ty.get_field_ty(&field).unwrap().clone())), TypeKind::CodegenPtr(Box::new(
struct_ty.get_field_ty(&field).unwrap().clone(),
)),
)) ))
} }
} }
mir::ExprKind::Struct(name, items) => { mir::ExprKind::Struct(name, items) => {
let type_key = CustomTypeKey(name.clone(), scope.module_id); let type_key = CustomTypeKey(name.clone(), scope.module_id);
let ty = Type::CustomType({ let struct_ty = Type::CustomType({
let Some(a) = scope.type_values.get(&type_key) else { let Some(a) = scope.type_values.get(&type_key) else {
return Ok(None); return Ok(None);
}; };
*a *a
}); });
let TypeDefinition {
kind: TypeDefinitionKind::Struct(struct_ty),
..
} = scope.types.get(scope.type_values.get(&type_key).unwrap()).unwrap();
let indices = struct_ty.0.iter().enumerate();
let load_n = format!("{}.load", name); let load_n = format!("{}.load", name);
let struct_ptr = scope let struct_ptr = scope
.block .block
.build_named(name, Instr::Alloca(ty.clone())) .build_named(name, Instr::Alloca(struct_ty.clone()))
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location); .maybe_location(&mut scope.block, location);
for (field_n, exp) in items { for (i, (field_n, exp)) in items.iter().enumerate() {
let gep_n = format!("{}.{}.gep", name, field_n); let gep_n = format!("{}.{}.gep", name, field_n);
let store_n = format!("{}.{}.store", name, field_n); let store_n = format!("{}.{}.store", name, field_n);
let i = indices.clone().find(|(_, f)| f.0 == *field_n).unwrap().0;
let elem_ptr = scope let elem_ptr = scope
.block .block
@ -1083,7 +1168,10 @@ impl mir::Expression {
} }
} }
let struct_val = scope.block.build_named(load_n, Instr::Load(struct_ptr, ty)).unwrap(); let struct_val = scope
.block
.build_named(load_n, Instr::Load(struct_ptr, struct_ty))
.unwrap();
Some(StackValue( Some(StackValue(
StackValueKind::Literal(struct_val), StackValueKind::Literal(struct_val),
@ -1134,7 +1222,10 @@ impl mir::Expression {
.block .block
.build_named( .build_named(
format!("{}.deref.inner", varref.1), format!("{}.deref.inner", varref.1),
Instr::Load(var_ptr_instr, inner.get_type(scope.type_values)), Instr::Load(
var_ptr_instr,
inner.get_type(scope.type_values),
),
) )
.unwrap(), .unwrap(),
), ),
@ -1162,14 +1253,17 @@ impl mir::Expression {
Some(val) Some(val)
} else { } else {
match (&val.1, type_kind) { match (&val.1, type_kind) {
(TypeKind::CodegenPtr(inner), TypeKind::UserPtr(_)) => match *inner.clone() { (TypeKind::CodegenPtr(inner), TypeKind::UserPtr(_)) => match *inner.clone()
{
TypeKind::UserPtr(_) => Some(StackValue( TypeKind::UserPtr(_) => Some(StackValue(
val.0.derive( val.0.derive(
scope scope
.block .block
.build(Instr::BitCast( .build(Instr::BitCast(
val.instr(), val.instr(),
Type::Ptr(Box::new(type_kind.get_type(scope.type_values))), Type::Ptr(Box::new(
type_kind.get_type(scope.type_values),
)),
)) ))
.unwrap(), .unwrap(),
), ),
@ -1184,7 +1278,10 @@ impl mir::Expression {
val.0.derive( val.0.derive(
scope scope
.block .block
.build(Instr::BitCast(val.instr(), type_kind.get_type(scope.type_values))) .build(Instr::BitCast(
val.instr(),
type_kind.get_type(scope.type_values),
))
.unwrap(), .unwrap(),
), ),
type_kind.clone(), type_kind.clone(),
@ -1193,7 +1290,10 @@ impl mir::Expression {
let cast_instr = val let cast_instr = val
.1 .1
.get_type(scope.type_values) .get_type(scope.type_values)
.cast_instruction(val.instr(), &type_kind.get_type(scope.type_values)) .cast_instruction(
val.instr(),
&type_kind.get_type(scope.type_values),
)
.unwrap(); .unwrap();
Some(StackValue( Some(StackValue(
@ -1213,7 +1313,11 @@ impl mir::Expression {
} }
impl mir::IfExpression { impl mir::IfExpression {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> { fn codegen<'ctx, 'a>(
&self,
scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> Result<Option<StackValue>, ErrorKind> {
let condition = self.0.codegen(scope, state)?.unwrap(); let condition = self.0.codegen(scope, state)?.unwrap();
// Create blocks // Create blocks
@ -1285,7 +1389,10 @@ impl mir::IfExpression {
incoming.extend(else_res.clone()); incoming.extend(else_res.clone());
let instr = scope let instr = scope
.block .block
.build_named("phi", Instr::Phi(incoming.iter().map(|i| i.instr()).collect())) .build_named(
"phi",
Instr::Phi(incoming.iter().map(|i| i.instr()).collect()),
)
.unwrap(); .unwrap();
use StackValueKind::*; use StackValueKind::*;

View File

@ -160,7 +160,9 @@ impl<'ctx> StackBinopDefinition<'ctx> {
self.return_ty.clone(), self.return_ty.clone(),
)) ))
} }
StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]), StackBinopFunctionKind::Intrinsic(fun) => {
fun.codegen(scope, &[lhs.instr(), rhs.instr()])
}
} }
} }
} }

View File

@ -7,11 +7,9 @@ use crate::{
ast::token_stream::{self, TokenRange}, ast::token_stream::{self, TokenRange},
codegen, codegen,
lexer::{self, Cursor, FullToken, Position}, lexer::{self, Cursor, FullToken, Position},
mir::{self, pass, typecheck, Metadata, SourceModuleId}, mir::{self, pass, Metadata, SourceModuleId},
}; };
use crate::mir::typecheck::ErrorKind as TypecheckError;
fn label(text: &str) -> &str { fn label(text: &str) -> &str {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
@ -28,9 +26,9 @@ pub enum ErrorKind {
#[error("{}{}", label("(Parsing) "), .0.kind)] #[error("{}{}", label("(Parsing) "), .0.kind)]
ParserError(#[from] mir::pass::Error<token_stream::Error>), ParserError(#[from] mir::pass::Error<token_stream::Error>),
#[error("{}{}", label("(TypeCheck) "), .0.kind)] #[error("{}{}", label("(TypeCheck) "), .0.kind)]
TypeCheckError(#[source] mir::pass::Error<typecheck::ErrorKind>), TypeCheckError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>),
#[error("{}{}", label("(TypeInference) "), .0.kind)] #[error("{}{}", label("(TypeInference) "), .0.kind)]
TypeInferenceError(#[source] mir::pass::Error<TypecheckError>), TypeInferenceError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>),
#[error("{}{}", label("(Linker) "), .0.kind)] #[error("{}{}", label("(Linker) "), .0.kind)]
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
#[error("{}{}", label("(Codegen) "), .0)] #[error("{}{}", label("(Codegen) "), .0)]
@ -38,11 +36,11 @@ pub enum ErrorKind {
} }
impl ErrorKind { impl ErrorKind {
pub fn from_typecheck(err: mir::pass::Error<typecheck::ErrorKind>) -> ErrorKind { pub fn from_typecheck(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind {
ErrorKind::TypeCheckError(err) ErrorKind::TypeCheckError(err)
} }
pub fn from_typeinference(err: mir::pass::Error<typecheck::ErrorKind>) -> ErrorKind { pub fn from_typeinference(err: mir::pass::Error<mir::typecheck::ErrorKind>) -> ErrorKind {
ErrorKind::TypeInferenceError(err) ErrorKind::TypeInferenceError(err)
} }
} }

View File

@ -41,7 +41,7 @@
//! - Debug Symbols //! - Debug Symbols
//! ``` //! ```
use std::{path::PathBuf, thread, time::Duration}; use std::path::PathBuf;
use ast::{ use ast::{
lexer::{self, FullToken, Token}, lexer::{self, FullToken, Token},
@ -50,9 +50,7 @@ use ast::{
use codegen::intrinsics::{form_intrinsic_binops, form_intrinsics}; use codegen::intrinsics::{form_intrinsic_binops, form_intrinsics};
use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError}; use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError};
use mir::{ use mir::{
linker::LinkerPass, linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
pass::BinopMap,
typecheck::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs},
}; };
use reid_lib::{compile::CompileOutput, Context}; use reid_lib::{compile::CompileOutput, Context};
@ -98,7 +96,11 @@ pub fn compile_module<'map>(
let mut statements = Vec::new(); let mut statements = Vec::new();
while !matches!(token_stream.peek().unwrap_or(Token::Eof), Token::Eof) { while !matches!(token_stream.peek().unwrap_or(Token::Eof), Token::Eof) {
let statement = ReidError::from_parser(token_stream.parse::<TopLevelStatement>(), map.clone(), module_id)?; let statement = ReidError::from_parser(
token_stream.parse::<TopLevelStatement>(),
map.clone(),
module_id,
)?;
statements.push(statement); statements.push(statement);
} }
@ -125,22 +127,8 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&context); dbg!(&context);
let mut binops = BinopMap::default();
for module in &mut context.modules { for module in &mut context.modules {
for intrinsic in form_intrinsic_binops() { for intrinsic in form_intrinsic_binops() {
binops
.set(
mir::pass::ScopeBinopKey {
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
operator: intrinsic.op,
},
mir::pass::ScopeBinopDef {
hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
operator: intrinsic.op,
return_ty: intrinsic.return_type.clone(),
},
)
.ok();
module.1.binop_defs.insert(0, intrinsic); module.1.binop_defs.insert(0, intrinsic);
} }
} }
@ -152,7 +140,7 @@ pub fn perform_all_passes<'map>(
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{:#}", &context); println!("{}", &context);
let state = context.pass(&mut LinkerPass { let state = context.pass(&mut LinkerPass {
module_map, module_map,
@ -162,7 +150,7 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{:-^100}", "LINKER OUTPUT"); println!("{:-^100}", "LINKER OUTPUT");
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{:#}", &context); println!("{}", &context);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&state); dbg!(&state);
@ -173,7 +161,7 @@ pub fn perform_all_passes<'map>(
)); ));
} }
let refs = TypeRefs::with_binops(binops); let refs = TypeRefs::default();
let state = context.pass(&mut TypeInference { refs: &refs })?; let state = context.pass(&mut TypeInference { refs: &refs })?;
@ -182,7 +170,7 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{}", &refs); println!("{}", &refs);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{:#}", &context); println!("{}", &context);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&state); dbg!(&state);
@ -202,7 +190,7 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{:-^100}", "TYPECHECKER OUTPUT"); println!("{:-^100}", "TYPECHECKER OUTPUT");
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{:#}", &context); println!("{}", &context);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&state); dbg!(&state);
@ -243,7 +231,7 @@ pub fn compile_and_pass<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{:-^100}", "FINAL OUTPUT"); println!("{:-^100}", "FINAL OUTPUT");
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{:#}", &mir_context); println!("{}", &mir_context);
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION"))); let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
let codegen_modules = match mir_context.codegen(&mut context) { let codegen_modules = match mir_context.codegen(&mut context) {

View File

@ -2,7 +2,24 @@ use std::fmt::{Debug, Display, Write};
use crate::pad_adapter::PadAdapter; use crate::pad_adapter::PadAdapter;
use super::{typecheck::typerefs::TypeRefs, *}; use super::{typerefs::TypeRefs, *};
impl Display for TypeRefs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (i, typeref) in self.type_refs.borrow().iter().enumerate() {
let idx = *typeref.borrow();
writeln!(
f,
"{:<3} = {:<3} = {:?} = {}",
i,
unsafe { *self.recurse_type_ref(idx).borrow() },
self.retrieve_type(idx),
TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self)
)?;
}
Ok(())
}
}
impl Display for Context { impl Display for Context {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -15,8 +32,6 @@ impl Display for Context {
impl Display for Module { impl Display for Module {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let is_alternate = f.alternate();
writeln!(f, "Module({}) ({}) {{", self.name, self.module_id)?; writeln!(f, "Module({}) ({}) {{", self.name, self.module_id)?;
let mut state = Default::default(); let mut state = Default::default();
@ -25,27 +40,9 @@ impl Display for Module {
for import in &self.imports { for import in &self.imports {
writeln!(inner_f, "{}", import)?; writeln!(inner_f, "{}", import)?;
} }
for binop in &self.binop_defs {
let intrinsic_binops = self
.binop_defs
.iter()
.filter(|b| matches!(b.fn_kind, FunctionDefinitionKind::Intrinsic(_)));
for binop in self
.binop_defs
.iter()
.filter(|b| !matches!(b.fn_kind, FunctionDefinitionKind::Intrinsic(_)))
{
writeln!(inner_f, "{}", binop)?; writeln!(inner_f, "{}", binop)?;
} }
if is_alternate {
writeln!(inner_f, "... <{}> intrinsic binary operators", intrinsic_binops.count())?;
} else {
for binop in intrinsic_binops {
writeln!(inner_f, "{}", binop)?;
}
}
for typedef in &self.typedefs { for typedef in &self.typedefs {
writeln!(inner_f, "{}", typedef)?; writeln!(inner_f, "{}", typedef)?;
} }
@ -172,14 +169,24 @@ impl Display for StmtKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
StmtKind::Let(var, mutable, block) => { StmtKind::Let(var, mutable, block) => {
write!(f, "let{} {} = {}", if *mutable { " mut" } else { "" }, var, block) write!(
f,
"let{} {} = {}",
if *mutable { " mut" } else { "" },
var,
block
)
} }
StmtKind::Set(var, expr) => write!(f, "{} = {}", var, expr), StmtKind::Set(var, expr) => write!(f, "{} = {}", var, expr),
StmtKind::Import(n) => write!(f, "import {}", n), StmtKind::Import(n) => write!(f, "import {}", n),
StmtKind::Expression(exp) => Display::fmt(exp, f), StmtKind::Expression(exp) => Display::fmt(exp, f),
StmtKind::While(while_statement) => { StmtKind::While(while_statement) => {
write!(f, "while {} {}", while_statement.condition, while_statement.block,) write!(
f,
"while {} {}",
while_statement.condition, while_statement.block,
)
} }
} }
} }
@ -199,12 +206,7 @@ impl Display for ExprKind {
match self { match self {
ExprKind::Variable(var) => Display::fmt(var, f), ExprKind::Variable(var) => Display::fmt(var, f),
ExprKind::Literal(lit) => Display::fmt(lit, f), ExprKind::Literal(lit) => Display::fmt(lit, f),
ExprKind::BinOp(op, lhs, rhs, ty) => { ExprKind::BinOp(op, lhs, rhs) => write!(f, "{} {} {}", lhs, op, rhs),
write!(f, "{} {} {} (= ", lhs, op, rhs)?;
Debug::fmt(ty, f)?;
f.write_char(')')?;
Ok(())
}
ExprKind::FunctionCall(fc) => Display::fmt(fc, f), ExprKind::FunctionCall(fc) => Display::fmt(fc, f),
ExprKind::If(if_exp) => Display::fmt(&if_exp, f), ExprKind::If(if_exp) => Display::fmt(&if_exp, f),
ExprKind::Block(block) => Display::fmt(block, f), ExprKind::Block(block) => Display::fmt(block, f),

View File

@ -1,6 +1,4 @@
use crate::util::maybe; use super::{pass::ScopeBinopDef, typecheck::ErrorKind, typerefs::TypeRefs, VagueType as Vague, *};
use super::{pass::ScopeBinopDef, typecheck::typerefs::TypeRefs, *};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ReturnTypeOther { pub enum ReturnTypeOther {
@ -14,18 +12,87 @@ pub enum ReturnTypeOther {
Loop, Loop,
} }
#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)]
pub enum NumValueError {
#[error("Cannot divide by zero")]
DivideZero,
}
enum BlockReturn<'b> {
Early(&'b Statement),
Normal(ReturnKind, &'b Option<Box<Expression>>),
}
impl TypeKind { impl TypeKind {
pub fn collapse_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
if self == other {
return Ok(self.clone());
}
match (self, other) {
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => {
match other {
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Integer)),
TypeKind::Vague(Vague::Integer) => Ok(TypeKind::Vague(Vague::Integer)),
TypeKind::I8
| TypeKind::I16
| TypeKind::I32
| TypeKind::I64
| TypeKind::I128
| TypeKind::U8
| TypeKind::U16
| TypeKind::U32
| TypeKind::U64
| TypeKind::U128 => Ok(other.clone()),
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
}
}
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => {
match other {
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)),
TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)),
TypeKind::F16
| TypeKind::F32B
| TypeKind::F32
| TypeKind::F64
| TypeKind::F80
| TypeKind::F128
| TypeKind::F128PPC => Ok(other.clone()),
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
}
}
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => {
Ok(other.clone())
}
(TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => {
// Extracted to give priority for other collapse-error
let collapsed = val1.collapse_into(val2)?;
if mut1 == mut2 {
Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2))
} else {
Err(ErrorKind::TypesDifferMutability(
self.clone(),
other.clone(),
))
}
}
(TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => {
Ok(TypeKind::UserPtr(Box::new(val1.collapse_into(val2)?)))
}
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
}
}
pub fn cast_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
if let Ok(collapsed) = self.collapse_into(other) {
Ok(collapsed)
} else {
let self_cat = self.category();
let other_cat = other.category();
match (self, other) {
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Ok(other.clone()),
(TypeKind::Char, TypeKind::U8) => Ok(other.clone()),
(TypeKind::U8, TypeKind::Char) => Ok(other.clone()),
_ => match (&self_cat, &other_cat) {
(TypeCategory::Integer, TypeCategory::Integer) => Ok(other.clone()),
(TypeCategory::Integer, TypeCategory::Real) => Ok(other.clone()),
(TypeCategory::Real, TypeCategory::Integer) => Ok(other.clone()),
(TypeCategory::Real, TypeCategory::Real) => Ok(other.clone()),
_ => Err(ErrorKind::NotCastableTo(self.clone(), other.clone())),
},
}
}
}
/// Return the type that is the result of a binary operator between two /// Return the type that is the result of a binary operator between two
/// values of this type /// values of this type
pub fn simple_binop_type(&self, op: &BinaryOperator) -> Option<TypeKind> { pub fn simple_binop_type(&self, op: &BinaryOperator) -> Option<TypeKind> {
@ -43,6 +110,20 @@ impl TypeKind {
}) })
} }
pub fn binop_type(
lhs: &TypeKind,
rhs: &TypeKind,
binop: &ScopeBinopDef,
) -> Option<(TypeKind, TypeKind, TypeKind)> {
let lhs_ty = lhs.collapse_into(&binop.hands.0);
let rhs_ty = rhs.collapse_into(&binop.hands.1);
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
Some((lhs_ty, rhs_ty, binop.return_ty.clone()))
} else {
None
}
}
/// Reverse of binop_type, where the given hint is the known required output /// Reverse of binop_type, where the given hint is the known required output
/// type of the binop, and the output is the hint for the lhs/rhs type. /// type of the binop, and the output is the hint for the lhs/rhs type.
pub fn simple_binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> { pub fn simple_binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> {
@ -60,6 +141,22 @@ impl TypeKind {
} }
} }
pub fn binop_hint(
&self,
lhs: &TypeKind,
rhs: &TypeKind,
binop: &ScopeBinopDef,
) -> Option<(TypeKind, TypeKind)> {
self.collapse_into(&binop.return_ty).ok()?;
let lhs_ty = lhs.collapse_into(&binop.hands.0);
let rhs_ty = rhs.collapse_into(&binop.hands.1);
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
Some((lhs_ty, rhs_ty))
} else {
None
}
}
pub fn signed(&self) -> bool { pub fn signed(&self) -> bool {
match self { match self {
TypeKind::Bool => false, TypeKind::Bool => false,
@ -200,9 +297,9 @@ impl TypeKind {
(lhs1, rhs1): (&TypeKind, &TypeKind), (lhs1, rhs1): (&TypeKind, &TypeKind),
(lhs2, rhs2): (&TypeKind, &TypeKind), (lhs2, rhs2): (&TypeKind, &TypeKind),
) -> Option<(TypeKind, TypeKind)> { ) -> Option<(TypeKind, TypeKind)> {
if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&lhs2), rhs1.narrow_into(&rhs2)) { if let (Ok(lhs), Ok(rhs)) = (lhs1.collapse_into(&lhs2), rhs1.collapse_into(&rhs2)) {
Some((lhs, rhs)) Some((lhs, rhs))
} else if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&rhs2), rhs1.narrow_into(&lhs2)) { } else if let (Ok(lhs), Ok(rhs)) = (lhs1.collapse_into(&rhs2), rhs1.collapse_into(&lhs2)) {
Some((rhs, lhs)) Some((rhs, lhs))
} else { } else {
None None
@ -268,6 +365,11 @@ impl StructType {
} }
} }
enum BlockReturn<'b> {
Early(&'b Statement),
Normal(ReturnKind, &'b Option<Box<Expression>>),
}
impl Block { impl Block {
fn return_expr(&self) -> Result<BlockReturn, ReturnTypeOther> { fn return_expr(&self) -> Result<BlockReturn, ReturnTypeOther> {
let mut early_return = None; let mut early_return = None;
@ -359,7 +461,10 @@ impl Statement {
expr.return_type(refs, mod_id)?, expr.return_type(refs, mod_id)?,
Err(ReturnTypeOther::Let(var.2 + expr.1)), Err(ReturnTypeOther::Let(var.2 + expr.1)),
), ),
Set(lhs, rhs) => if_hard(rhs.return_type(refs, mod_id)?, Err(ReturnTypeOther::Set(lhs.1 + rhs.1))), Set(lhs, rhs) => if_hard(
rhs.return_type(refs, mod_id)?,
Err(ReturnTypeOther::Set(lhs.1 + rhs.1)),
),
Import(_) => todo!(), Import(_) => todo!(),
Expression(expression) => expression.return_type(refs, mod_id), Expression(expression) => expression.return_type(refs, mod_id),
While(_) => Err(ReturnTypeOther::Loop), While(_) => Err(ReturnTypeOther::Loop),
@ -387,14 +492,11 @@ impl Expression {
match &self.0 { match &self.0 {
Literal(lit) => Ok((ReturnKind::Soft, lit.as_type())), Literal(lit) => Ok((ReturnKind::Soft, lit.as_type())),
Variable(var) => var.return_type(), Variable(var) => var.return_type(),
BinOp(_, then_e, else_e, return_ty) => { BinOp(_, then_e, else_e) => {
let then_r = then_e.return_type(refs, mod_id)?; let then_r = then_e.return_type(refs, mod_id)?;
let else_r = else_e.return_type(refs, mod_id)?; let else_r = else_e.return_type(refs, mod_id)?;
Ok(match (then_r.0, else_r.0) { Ok(pick_return(then_r, else_r))
(ReturnKind::Hard, ReturnKind::Hard) => (ReturnKind::Hard, return_ty.clone()),
_ => (ReturnKind::Soft, return_ty.clone()),
})
} }
Block(block) => block.return_type(refs, mod_id), Block(block) => block.return_type(refs, mod_id),
FunctionCall(fcall) => fcall.return_type(), FunctionCall(fcall) => fcall.return_type(),
@ -457,14 +559,22 @@ impl Expression {
ExprKind::Array(_) => None, ExprKind::Array(_) => None,
ExprKind::Struct(_, _) => None, ExprKind::Struct(_, _) => None,
ExprKind::Literal(_) => None, ExprKind::Literal(_) => None,
ExprKind::BinOp(_, _, _, _) => None, ExprKind::BinOp(_, _, _) => None,
ExprKind::FunctionCall(_) => None, ExprKind::FunctionCall(_) => None,
ExprKind::If(_) => None, ExprKind::If(_) => None,
ExprKind::CastTo(expression, _) => expression.backing_var(), ExprKind::CastTo(expression, _) => expression.backing_var(),
} }
} }
pub fn num_value(&self) -> Result<Option<i128>, NumValueError> { pub fn is_zero(&self) -> Result<Option<bool>, ErrorKind> {
if let Some(val) = self.num_value()? {
Ok(Some(val == 0))
} else {
Ok(None)
}
}
pub fn num_value(&self) -> Result<Option<i128>, ErrorKind> {
Ok(match &self.0 { Ok(match &self.0 {
ExprKind::Variable(_) => None, ExprKind::Variable(_) => None,
ExprKind::Indexed(..) => None, ExprKind::Indexed(..) => None,
@ -472,7 +582,7 @@ impl Expression {
ExprKind::Array(_) => None, ExprKind::Array(_) => None,
ExprKind::Struct(..) => None, ExprKind::Struct(..) => None,
ExprKind::Literal(literal) => literal.num_value(), ExprKind::Literal(literal) => literal.num_value(),
ExprKind::BinOp(op, lhs, rhs, _) => match op { ExprKind::BinOp(op, lhs, rhs) => match op {
BinaryOperator::Add => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a + b), BinaryOperator::Add => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a + b),
BinaryOperator::Minus => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a - b), BinaryOperator::Minus => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a - b),
BinaryOperator::Mult => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a * b), BinaryOperator::Mult => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a * b),
@ -481,14 +591,14 @@ impl Expression {
BinaryOperator::Div => { BinaryOperator::Div => {
let rhs_value = rhs.num_value()?; let rhs_value = rhs.num_value()?;
if rhs_value == Some(0) { if rhs_value == Some(0) {
Err(NumValueError::DivideZero)? Err(ErrorKind::DivideZero)?
} }
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b) maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b)
} }
BinaryOperator::Mod => { BinaryOperator::Mod => {
let rhs_value = rhs.num_value()?; let rhs_value = rhs.num_value()?;
if rhs_value == Some(0) { if rhs_value == Some(0) {
Err(NumValueError::DivideZero)? Err(ErrorKind::DivideZero)?
} }
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a % b) maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a % b)
} }
@ -503,6 +613,16 @@ impl Expression {
} }
} }
fn maybe<T>(lhs: Option<i128>, rhs: Option<i128>, fun: T) -> Option<i128>
where
T: FnOnce(i128, i128) -> i128,
{
if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
Some(fun(lhs, rhs))
} else {
None
}
}
impl IfExpression { impl IfExpression {
pub fn return_type( pub fn return_type(
&self, &self,
@ -558,6 +678,56 @@ pub fn pick_return<T>(lhs: (ReturnKind, T), rhs: (ReturnKind, T)) -> (ReturnKind
} }
} }
impl TypeKind {
/// Assert that a type is already known and not vague. Return said type or
/// error.
pub fn assert_unvague(&self) -> Result<TypeKind, ErrorKind> {
self.known().map_err(ErrorKind::TypeIsVague)
}
/// Try to collapse a type on itself producing a default type if one exists,
/// Error if not.
pub fn or_default(&self) -> Result<TypeKind, ErrorKind> {
Ok(match self {
TypeKind::Vague(vague_type) => match &vague_type {
Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type))?,
Vague::Integer => TypeKind::I32,
Vague::TypeRef(_) => panic!("Hinted default!"),
VagueType::Decimal => TypeKind::F32,
},
TypeKind::Array(type_kind, len) => {
TypeKind::Array(Box::new(type_kind.or_default()?), *len)
}
TypeKind::Borrow(type_kind, mutable) => {
TypeKind::Borrow(Box::new(type_kind.or_default()?), *mutable)
}
TypeKind::UserPtr(type_kind) => TypeKind::UserPtr(Box::new(type_kind.or_default()?)),
TypeKind::CodegenPtr(type_kind) => {
TypeKind::CodegenPtr(Box::new(type_kind.or_default()?))
}
_ => self.clone(),
})
}
pub fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind {
match self {
TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_type(*idx).unwrap(),
_ => self.clone(),
}
}
pub fn resolve_ref(&self, refs: &TypeRefs) -> TypeKind {
let resolved = self.resolve_weak(refs);
match resolved {
TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_ref(refs)), len),
TypeKind::Borrow(inner, mutable) => {
TypeKind::Borrow(Box::new(inner.resolve_ref(refs)), mutable)
}
_ => resolved,
}
}
}
impl Literal { impl Literal {
pub fn num_value(&self) -> Option<i128> { pub fn num_value(&self) -> Option<i128> {
match self { match self {
@ -604,7 +774,9 @@ pub enum EqualsIssue {
impl FunctionDefinition { impl FunctionDefinition {
pub fn equals_as_imported(&self, other: &FunctionDefinition) -> Result<(), EqualsIssue> { pub fn equals_as_imported(&self, other: &FunctionDefinition) -> Result<(), EqualsIssue> {
match &self.kind { match &self.kind {
FunctionDefinitionKind::Local(_, metadata) => Err(EqualsIssue::ExistsLocally(*metadata)), FunctionDefinitionKind::Local(_, metadata) => {
Err(EqualsIssue::ExistsLocally(*metadata))
}
FunctionDefinitionKind::Extern(imported) => { FunctionDefinitionKind::Extern(imported) => {
if *imported { if *imported {
Err(EqualsIssue::ConflictWithImport(self.name.clone())) Err(EqualsIssue::ConflictWithImport(self.name.clone()))
@ -616,7 +788,10 @@ impl FunctionDefinition {
{ {
Ok(()) Ok(())
} else { } else {
Err(EqualsIssue::AlreadyExtern(self.name.clone(), self.signature())) Err(EqualsIssue::AlreadyExtern(
self.name.clone(),
self.signature(),
))
} }
} }
} }

View File

@ -15,6 +15,8 @@ pub mod implement;
pub mod linker; pub mod linker;
pub mod pass; pub mod pass;
pub mod typecheck; pub mod typecheck;
pub mod typeinference;
pub mod typerefs;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
pub struct SourceModuleId(pub u32); pub struct SourceModuleId(pub u32);
@ -112,9 +114,7 @@ pub enum TypeKind {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum VagueType { pub enum VagueType {
Unknown, Unknown,
/// Some integer value (e.g. 5)
Integer, Integer,
/// Some decimal fractional value (e.g. 1.5)
Decimal, Decimal,
TypeRef(usize), TypeRef(usize),
} }
@ -256,7 +256,7 @@ pub enum ExprKind {
Array(Vec<Expression>), Array(Vec<Expression>),
Struct(String, Vec<(String, Expression)>), Struct(String, Vec<(String, Expression)>),
Literal(Literal), Literal(Literal),
BinOp(BinaryOperator, Box<Expression>, Box<Expression>, TypeKind), BinOp(BinaryOperator, Box<Expression>, Box<Expression>),
FunctionCall(FunctionCall), FunctionCall(FunctionCall),
If(IfExpression), If(IfExpression),
Block(Block), Block(Block),
@ -270,7 +270,11 @@ pub struct Expression(pub ExprKind, pub Metadata);
/// Condition, Then, Else /// Condition, Then, Else
#[derive(Debug)] #[derive(Debug)]
pub struct IfExpression(pub Box<Expression>, pub Box<Expression>, pub Box<Option<Expression>>); pub struct IfExpression(
pub Box<Expression>,
pub Box<Expression>,
pub Box<Option<Expression>>,
);
#[derive(Debug)] #[derive(Debug)]
pub struct FunctionCall { pub struct FunctionCall {

View File

@ -5,7 +5,6 @@ use std::collections::HashMap;
use std::convert::Infallible; use std::convert::Infallible;
use std::error::Error as STDError; use std::error::Error as STDError;
use crate::codegen::intrinsics::form_intrinsic_binops;
use crate::error_raporting::ReidError; use crate::error_raporting::ReidError;
use super::*; use super::*;
@ -54,7 +53,12 @@ impl<TErr: STDError> State<TErr> {
} }
} }
fn or_else<U, T: Into<Metadata> + Clone + Copy>(&mut self, result: Result<U, TErr>, default: U, meta: T) -> U { fn or_else<U, T: Into<Metadata> + Clone + Copy>(
&mut self,
result: Result<U, TErr>,
default: U,
meta: T,
) -> U {
match result { match result {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
@ -67,7 +71,11 @@ impl<TErr: STDError> State<TErr> {
} }
} }
fn ok<T: Into<Metadata> + Clone + Copy, U>(&mut self, result: Result<U, TErr>, meta: T) -> Option<U> { fn ok<T: Into<Metadata> + Clone + Copy, U>(
&mut self,
result: Result<U, TErr>,
meta: T,
) -> Option<U> {
match result { match result {
Ok(v) => Some(v), Ok(v) => Some(v),
Err(e) => { Err(e) => {
@ -111,17 +119,11 @@ impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> {
pub fn find(&self, key: &Key) -> Option<(&Key, &T)> { pub fn find(&self, key: &Key) -> Option<(&Key, &T)> {
self.0.iter().find(|(k, _)| *k == key) self.0.iter().find(|(k, _)| *k == key)
} }
pub fn filter(&self, key: &Key) -> Vec<(&Key, &T)> {
self.0.iter().filter(|(k, _)| *k == key).collect()
}
} }
pub type BinopMap = Storage<ScopeBinopKey, ScopeBinopDef>;
#[derive(Clone, Default, Debug)] #[derive(Clone, Default, Debug)]
pub struct Scope<Data: Clone + Default> { pub struct Scope<Data: Clone + Default> {
pub binops: BinopMap, pub binops: Storage<ScopeBinopKey, ScopeBinopDef>,
pub function_returns: Storage<String, ScopeFunction>, pub function_returns: Storage<String, ScopeFunction>,
pub variables: Storage<String, ScopeVariable>, pub variables: Storage<String, ScopeVariable>,
pub types: Storage<CustomTypeKey, TypeDefinition>, pub types: Storage<CustomTypeKey, TypeDefinition>,
@ -191,12 +193,8 @@ impl PartialEq for ScopeBinopKey {
if self.operator.is_commutative() != other.operator.is_commutative() { if self.operator.is_commutative() != other.operator.is_commutative() {
return false; return false;
} }
let operators_eq = self.params == other.params;
let operators_eq = let swapped_ops_eq = (self.params.1.clone(), self.params.0.clone()) == other.params;
self.params.0.narrow_into(&other.params.0).is_ok() && self.params.1.narrow_into(&other.params.1).is_ok();
let swapped_ops_eq =
self.params.0.narrow_into(&other.params.1).is_ok() && self.params.1.narrow_into(&other.params.0).is_ok();
if self.operator.is_commutative() { if self.operator.is_commutative() {
operators_eq || swapped_ops_eq operators_eq || swapped_ops_eq
} else { } else {
@ -225,18 +223,6 @@ pub struct ScopeBinopDef {
pub return_ty: TypeKind, pub return_ty: TypeKind,
} }
impl ScopeBinopDef {
pub fn narrow(&self, lhs: &TypeKind, rhs: &TypeKind) -> Option<(TypeKind, TypeKind, TypeKind)> {
let lhs_ty = lhs.narrow_into(&self.hands.0);
let rhs_ty = rhs.narrow_into(&self.hands.1);
if let (Ok(lhs_ty), Ok(rhs_ty)) = (lhs_ty, rhs_ty) {
Some((lhs_ty, rhs_ty, self.return_ty.clone()))
} else {
None
}
}
}
pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> { pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> {
state: &'st mut State<TError>, state: &'st mut State<TError>,
pub scope: &'sc mut Scope<Data>, pub scope: &'sc mut Scope<Data>,
@ -245,7 +231,11 @@ pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone>
} }
impl<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> PassState<'st, 'sc, Data, TError> { impl<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> PassState<'st, 'sc, Data, TError> {
fn from(state: &'st mut State<TError>, scope: &'sc mut Scope<Data>, module_id: Option<SourceModuleId>) -> Self { fn from(
state: &'st mut State<TError>,
scope: &'sc mut Scope<Data>,
module_id: Option<SourceModuleId>,
) -> Self {
PassState { PassState {
state, state,
scope, scope,
@ -263,11 +253,19 @@ impl<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> PassState<'st, '
self.state.or_else(result, default, meta) self.state.or_else(result, default, meta)
} }
pub fn ok<TMeta: Into<Metadata> + Clone + Copy, U>(&mut self, result: Result<U, TError>, meta: TMeta) -> Option<U> { pub fn ok<TMeta: Into<Metadata> + Clone + Copy, U>(
&mut self,
result: Result<U, TError>,
meta: TMeta,
) -> Option<U> {
self.state.ok(result, meta) self.state.ok(result, meta)
} }
pub fn note_errors<TMeta: Into<Metadata> + Clone>(&mut self, errors: &Vec<TError>, meta: TMeta) { pub fn note_errors<TMeta: Into<Metadata> + Clone>(
&mut self,
errors: &Vec<TError>,
meta: TMeta,
) {
for error in errors { for error in errors {
self.ok::<_, Infallible>(Err(error.clone()), meta.clone().into()); self.ok::<_, Infallible>(Err(error.clone()), meta.clone().into());
} }
@ -291,10 +289,18 @@ pub trait Pass {
type Data: Clone + Default; type Data: Clone + Default;
type TError: STDError + Clone; type TError: STDError + Clone;
fn context(&mut self, _context: &mut Context, mut _state: PassState<Self::Data, Self::TError>) -> PassResult { fn context(
&mut self,
_context: &mut Context,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(()) Ok(())
} }
fn module(&mut self, _module: &mut Module, mut _state: PassState<Self::Data, Self::TError>) -> PassResult { fn module(
&mut self,
_module: &mut Module,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(()) Ok(())
} }
fn function( fn function(
@ -304,13 +310,25 @@ pub trait Pass {
) -> PassResult { ) -> PassResult {
Ok(()) Ok(())
} }
fn block(&mut self, _block: &mut Block, mut _state: PassState<Self::Data, Self::TError>) -> PassResult { fn block(
&mut self,
_block: &mut Block,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(()) Ok(())
} }
fn stmt(&mut self, _stmt: &mut Statement, mut _state: PassState<Self::Data, Self::TError>) -> PassResult { fn stmt(
&mut self,
_stmt: &mut Statement,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(()) Ok(())
} }
fn expr(&mut self, _expr: &mut Expression, mut _state: PassState<Self::Data, Self::TError>) -> PassResult { fn expr(
&mut self,
_expr: &mut Expression,
mut _state: PassState<Self::Data, Self::TError>,
) -> PassResult {
Ok(()) Ok(())
} }
} }
@ -320,24 +338,6 @@ impl Context {
let mut state = State::new(); let mut state = State::new();
let mut scope = Scope::default(); let mut scope = Scope::default();
pass.context(self, PassState::from(&mut state, &mut scope, None))?; pass.context(self, PassState::from(&mut state, &mut scope, None))?;
for intrinsic in form_intrinsic_binops() {
scope
.binops
.set(
ScopeBinopKey {
params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
operator: intrinsic.op,
},
ScopeBinopDef {
hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
operator: intrinsic.op,
return_ty: intrinsic.return_type.clone(),
},
)
.ok();
}
for (_, module) in &mut self.modules { for (_, module) in &mut self.modules {
module.pass(pass, &mut state, &mut scope.inner())?; module.pass(pass, &mut state, &mut scope.inner())?;
} }
@ -346,7 +346,12 @@ 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 {
for typedef in &self.typedefs { for typedef in &self.typedefs {
scope scope
.types .types

View File

@ -6,17 +6,84 @@ use crate::{mir::*, util::try_all};
use VagueType as Vague; use VagueType as Vague;
use super::{ use super::{
super::pass::{Pass, PassResult, ScopeVariable}, pass::{Pass, PassResult, PassState, ScopeVariable},
typerefs::TypeRefs, typerefs::TypeRefs,
ErrorKind, HintKind, TypecheckPassState,
}; };
#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)]
pub enum ErrorKind {
#[error("NULL error, should never occur!")]
Null,
#[error("Type is vague: {0}")]
TypeIsVague(VagueType),
#[error("Literal {0} can not be coerced to type {1}")]
LiteralIncompatible(Literal, TypeKind),
#[error("Types {0} and {1} are incompatible")]
TypesIncompatible(TypeKind, TypeKind),
#[error("Variable not defined: {0}")]
VariableNotDefined(String),
#[error("Function not defined: {0}")]
FunctionNotDefined(String),
#[error("Expected a return type of {0}, got {1} instead")]
ReturnTypeMismatch(TypeKind, TypeKind),
#[error("Function {0} already defined {1}")]
FunctionAlreadyDefined(String, ErrorTypedefKind),
#[error("Variable already defined: {0}")]
VariableAlreadyDefined(String),
#[error("Variable {0} is not declared as mutable")]
VariableNotMutable(String),
#[error("Function {0} was given {1} parameters, but {2} were expected")]
InvalidAmountParameters(String, usize, usize),
#[error("Unable to infer type {0}")]
TypeNotInferrable(TypeKind),
#[error("Expected branch type to be {0}, found {1} instead")]
BranchTypesDiffer(TypeKind, TypeKind),
#[error("Attempted to index a non-indexable type of {0}")]
TriedIndexingNonIndexable(TypeKind),
#[error("Index {0} out of bounds ({1})")]
IndexOutOfBounds(u64, u64),
#[error("No such type {0} could be found in module {1}")]
NoSuchType(String, SourceModuleId),
#[error("Attempted to access field of non-struct type of {0}")]
TriedAccessingNonStruct(TypeKind),
#[error("No such struct-field on type {0}")]
NoSuchField(String),
#[error("Struct field declared twice {0}")]
DuplicateStructField(String),
#[error("Type declared twice {0}")]
DuplicateTypeName(String),
#[error("Recursive type definition: {0}.{1}")]
RecursiveTypeDefinition(String, String),
#[error("This type of expression can not be used for assignment")]
InvalidSetExpression,
#[error("Can not deref {0}, as it is not a borrow")]
AttemptedDerefNonBorrow(String),
#[error("Types {0} and {1} differ in mutability")]
TypesDifferMutability(TypeKind, TypeKind),
#[error("Cannot mutably borrow variable {0}, which is not declared as mutable")]
ImpossibleMutableBorrow(String),
#[error("Cannot declare variable {0} as mutable, when it's type is immutable")]
ImpossibleMutLet(String),
#[error("Cannot produce a negative unsigned value of type {0}")]
NegativeUnsignedValue(TypeKind),
#[error("Cannot cast type {0} into type {1}")]
NotCastableTo(TypeKind, TypeKind),
#[error("Cannot divide by zero")]
DivideZero,
#[error("Binary operation {0} between {1} and {2} is already defined")]
BinaryOpAlreadyDefined(BinaryOperator, TypeKind, TypeKind),
#[error("Binary operation {0} between {1} and {2} is not defined")]
InvalidBinop(BinaryOperator, TypeKind, TypeKind),
}
/// Struct used to implement a type-checking pass that can be performed on the /// Struct used to implement a type-checking pass that can be performed on the
/// MIR. /// MIR.
pub struct TypeCheck<'t> { pub struct TypeCheck<'t> {
pub refs: &'t TypeRefs, pub refs: &'t TypeRefs,
} }
type TypecheckPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ErrorTypedefKind { pub enum ErrorTypedefKind {
#[error("locally")] #[error("locally")]
@ -56,7 +123,10 @@ impl<'t> Pass for TypeCheck<'t> {
} }
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(),
);
} }
} }
@ -91,7 +161,10 @@ fn check_typedefs_for_recursion<'a, 'b>(
if let TypeKind::CustomType(CustomTypeKey(name, _)) = field_ty { if let TypeKind::CustomType(CustomTypeKey(name, _)) = field_ty {
if seen.contains(name) { if seen.contains(name) {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
Err(ErrorKind::RecursiveTypeDefinition(typedef.name.clone(), name.clone())), Err(ErrorKind::RecursiveTypeDefinition(
typedef.name.clone(),
name.clone(),
)),
typedef.meta, typedef.meta,
); );
} else { } else {
@ -107,7 +180,11 @@ fn check_typedefs_for_recursion<'a, 'b>(
} }
impl BinopDefinition { impl BinopDefinition {
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> { fn typecheck(
&mut self,
typerefs: &TypeRefs,
state: &mut TypecheckPassState,
) -> Result<TypeKind, ErrorKind> {
for param in vec![&self.lhs, &self.rhs] { for param in vec![&self.lhs, &self.rhs] {
let param_t = state.or_else( let param_t = state.or_else(
param.1.assert_known(typerefs, state), param.1.assert_known(typerefs, state),
@ -131,21 +208,29 @@ impl BinopDefinition {
let return_type = self.return_type.clone().assert_known(typerefs, state)?; let return_type = self.return_type.clone().assert_known(typerefs, state)?;
state.scope.return_type_hint = Some(self.return_type.clone()); state.scope.return_type_hint = Some(self.return_type.clone());
let inferred = self let inferred =
.fn_kind self.fn_kind
.typecheck(&typerefs, &mut state.inner(), Some(return_type.clone())); .typecheck(&typerefs, &mut state.inner(), Some(return_type.clone()));
match inferred { match inferred {
Ok(t) => return_type Ok(t) => return_type
.narrow_into(&t.1) .collapse_into(&t.1)
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))), .or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta().unwrap_or(self.signature()))), Err(e) => Ok(state.or_else(
Err(e),
return_type,
self.block_meta().unwrap_or(self.signature()),
)),
} }
} }
} }
impl FunctionDefinition { impl FunctionDefinition {
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> { fn typecheck(
&mut self,
typerefs: &TypeRefs,
state: &mut TypecheckPassState,
) -> Result<TypeKind, ErrorKind> {
for param in &self.parameters { for param in &self.parameters {
let param_t = state.or_else( let param_t = state.or_else(
param.1.assert_known(typerefs, state), param.1.assert_known(typerefs, state),
@ -167,11 +252,13 @@ impl FunctionDefinition {
} }
let return_type = self.return_type.clone().assert_known(typerefs, state)?; let return_type = self.return_type.clone().assert_known(typerefs, state)?;
let inferred = self.kind.typecheck(typerefs, state, Some(self.return_type.clone())); let inferred = self
.kind
.typecheck(typerefs, state, Some(self.return_type.clone()));
match inferred { match inferred {
Ok(t) => return_type Ok(t) => return_type
.narrow_into(&t.1) .collapse_into(&t.1)
.or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))), .or(Err(ErrorKind::ReturnTypeMismatch(return_type, t.1))),
Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta())), Err(e) => Ok(state.or_else(Err(e), return_type, self.block_meta())),
} }
@ -188,10 +275,14 @@ impl FunctionDefinitionKind {
match self { match self {
FunctionDefinitionKind::Local(block, _) => { FunctionDefinitionKind::Local(block, _) => {
state.scope.return_type_hint = hint.clone(); state.scope.return_type_hint = hint.clone();
block.typecheck(&mut state.inner(), &typerefs, hint.into()) block.typecheck(&mut state.inner(), &typerefs, hint.as_ref())
}
FunctionDefinitionKind::Extern(_) => {
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
}
FunctionDefinitionKind::Intrinsic(..) => {
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
} }
FunctionDefinitionKind::Extern(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
FunctionDefinitionKind::Intrinsic(..) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
} }
} }
} }
@ -201,7 +292,7 @@ impl Block {
&mut self, &mut self,
state: &mut TypecheckPassState, state: &mut TypecheckPassState,
typerefs: &TypeRefs, typerefs: &TypeRefs,
hint_t: HintKind, hint_t: Option<&TypeKind>,
) -> Result<(ReturnKind, TypeKind), ErrorKind> { ) -> Result<(ReturnKind, TypeKind), ErrorKind> {
let mut state = state.inner(); let mut state = state.inner();
@ -217,17 +308,16 @@ 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, Some(&var_t_resolved));
// If expression resolution itself was erronous, resolve as // If expression resolution itself was erronous, resolve as
// Unknown and note error. // Unknown and note error.
let res = state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1); let res = state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1);
// Make sure the expression and variable type really is the same // Make sure the expression and variable type really is the same
let res_t = state.or_else( let res_t = state.or_else(
res.narrow_into(&var_t_resolved), res.collapse_into(&var_t_resolved),
TypeKind::Vague(Vague::Unknown), TypeKind::Vague(Vague::Unknown),
variable_reference.2 + expression.1, variable_reference.2 + expression.1,
); );
@ -248,7 +338,7 @@ impl Block {
); );
// Re-typecheck and coerce expression to default type // Re-typecheck and coerce expression to default type
let expr_res = expression.typecheck(&mut state, &typerefs, HintKind::Coerce(res_t.clone())); let expr_res = expression.typecheck(&mut state, &typerefs, Some(&res_t));
state.ok(expr_res, expression.1); state.ok(expr_res, expression.1);
res_t res_t
@ -270,19 +360,21 @@ impl Block {
mutable: *mutable, mutable: *mutable,
}, },
) )
.or(Err(ErrorKind::VariableAlreadyDefined(variable_reference.1.clone()))); .or(Err(ErrorKind::VariableAlreadyDefined(
variable_reference.1.clone(),
)));
state.ok(res, variable_reference.2); state.ok(res, variable_reference.2);
None None
} }
StmtKind::Set(lhs, rhs) => { StmtKind::Set(lhs, rhs) => {
// Typecheck expression and coerce to variable type // Typecheck expression and coerce to variable type
let lhs_res = lhs.typecheck(&mut state, typerefs, HintKind::Default); let lhs_res = lhs.typecheck(&mut state, typerefs, None);
// If expression resolution itself was erronous, resolve as // If expression resolution itself was erronous, resolve as
// Unknown. // Unknown.
let lhs_ty = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1); let lhs_ty = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
// Typecheck expression and coerce to variable type // Typecheck expression and coerce to variable type
let res = rhs.typecheck(&mut state, &typerefs, HintKind::Coerce(lhs_ty.clone())); let res = rhs.typecheck(&mut state, &typerefs, Some(&lhs_ty));
// If expression resolution itself was erronous, resolve as // If expression resolution itself was erronous, resolve as
// Unknown. // Unknown.
@ -290,7 +382,7 @@ impl Block {
// Make sure the expression and variable type to really // Make sure the expression and variable type to really
// be the same // be the same
state.ok(lhs_ty.narrow_into(&rhs_ty), lhs.1 + rhs.1); state.ok(lhs_ty.collapse_into(&rhs_ty), lhs.1 + rhs.1);
if let Some(named_var) = lhs.backing_var() { if let Some(named_var) = lhs.backing_var() {
if let Some(scope_var) = state.scope.variables.get(&named_var.1) { if let Some(scope_var) = state.scope.variables.get(&named_var.1) {
@ -317,21 +409,31 @@ impl Block {
} }
StmtKind::Import(_) => todo!(), StmtKind::Import(_) => todo!(),
StmtKind::Expression(expression) => { StmtKind::Expression(expression) => {
let res = expression.typecheck(&mut state, &typerefs, HintKind::None); let res = expression.typecheck(&mut state, &typerefs, None);
state.or_else(res, TypeKind::Void, expression.1); state.or_else(res, TypeKind::Void, expression.1);
if let Ok((kind, _)) = expression.return_type(typerefs, state.module_id.unwrap()) { if let Ok((kind, _)) =
expression.return_type(typerefs, state.module_id.unwrap())
{
Some((kind, expression)) Some((kind, expression))
} else { } else {
None None
} }
} }
StmtKind::While(WhileStatement { condition, block, meta }) => { StmtKind::While(WhileStatement {
let condition_ty = condition.typecheck(&mut state, typerefs, HintKind::Coerce(TypeKind::Bool))?; condition,
block,
meta,
}) => {
let condition_ty =
condition.typecheck(&mut state, typerefs, Some(&TypeKind::Bool))?;
if condition_ty.assert_known(typerefs, &state)? != TypeKind::Bool { if condition_ty.assert_known(typerefs, &state)? != TypeKind::Bool {
state.note_errors(&vec![ErrorKind::TypesIncompatible(condition_ty, TypeKind::Bool)], *meta); state.note_errors(
&vec![ErrorKind::TypesIncompatible(condition_ty, TypeKind::Bool)],
*meta,
);
} }
block.typecheck(&mut state, typerefs, HintKind::None)?; block.typecheck(&mut state, typerefs, None)?;
None None
} }
@ -347,7 +449,7 @@ impl Block {
// block) // block)
if let Some((ReturnKind::Hard, expr)) = early_return { if let Some((ReturnKind::Hard, expr)) = early_return {
let hint = state.scope.return_type_hint.clone(); let hint = state.scope.return_type_hint.clone();
let res = expr.typecheck(&mut state, &typerefs, hint.into()); let res = expr.typecheck(&mut state, &typerefs, hint.as_ref());
return Ok(( return Ok((
ReturnKind::Hard, ReturnKind::Hard,
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1), state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
@ -357,11 +459,11 @@ impl Block {
if let Some((return_kind, expr)) = &mut self.return_expression { if let Some((return_kind, expr)) = &mut self.return_expression {
// Use function return type as hint if return is hard. // Use function return type as hint if return is hard.
let ret_hint_t = match return_kind { let ret_hint_t = match return_kind {
ReturnKind::Hard => state.scope.return_type_hint.clone().into(), ReturnKind::Hard => state.scope.return_type_hint.clone(),
ReturnKind::Soft => hint_t, ReturnKind::Soft => hint_t.cloned(),
}; };
if let Some(expr) = expr { if let Some(expr) = expr {
let res = expr.typecheck(&mut state, &typerefs, ret_hint_t.into()); let res = expr.typecheck(&mut state, &typerefs, ret_hint_t.as_ref());
Ok(( Ok((
*return_kind, *return_kind,
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1), state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
@ -380,7 +482,7 @@ impl Expression {
&mut self, &mut self,
state: &mut TypecheckPassState, state: &mut TypecheckPassState,
typerefs: &TypeRefs, typerefs: &TypeRefs,
hint_t: HintKind, hint_t: Option<&TypeKind>,
) -> Result<TypeKind, ErrorKind> { ) -> Result<TypeKind, ErrorKind> {
match &mut self.0 { match &mut self.0 {
ExprKind::Variable(var_ref) => { ExprKind::Variable(var_ref) => {
@ -400,7 +502,7 @@ impl Expression {
// Update typing to be more accurate // Update typing to be more accurate
var_ref.0 = state.or_else( var_ref.0 = state.or_else(
var_ref.0.resolve_ref(typerefs).narrow_into(&existing), var_ref.0.resolve_ref(typerefs).collapse_into(&existing),
TypeKind::Vague(Vague::Unknown), TypeKind::Vague(Vague::Unknown),
var_ref.2, var_ref.2,
); );
@ -408,41 +510,82 @@ impl Expression {
Ok(var_ref.0.clone()) Ok(var_ref.0.clone())
} }
ExprKind::Literal(literal) => { ExprKind::Literal(literal) => {
*literal = literal.clone().try_coerce(hint_t)?; *literal = literal.clone().try_coerce(hint_t.cloned())?;
Ok(literal.as_type()) Ok(literal.as_type())
} }
ExprKind::BinOp(op, lhs, rhs, ret_ty) => { ExprKind::BinOp(op, lhs, rhs) => {
// First find unfiltered parameters to binop // First find unfiltered parameters to binop
let lhs_res = lhs.typecheck(state, &typerefs, HintKind::None); let lhs_res = lhs.typecheck(state, &typerefs, None);
let rhs_res = rhs.typecheck(state, &typerefs, HintKind::None);
let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1); let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
let rhs_res = rhs.typecheck(state, &typerefs, None);
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1); let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
let mut expected_return_ty = ret_ty.resolve_ref(typerefs); let cloned = state.scope.binops.clone();
if let HintKind::Coerce(hint_t) = hint_t { let mut iter = cloned.iter();
expected_return_ty = state.or_else( let operator = loop {
expected_return_ty.narrow_into(&hint_t), let Some((_, binop)) = iter.next() else {
TypeKind::Vague(VagueType::Unknown), break None;
self.1, };
); if binop.operator != *op {
continue;
}
if let Some(hint_t) = hint_t {
if binop.return_ty == *hint_t {
if let Some(_) = TypeKind::binop_type(&lhs_type, &rhs_type, binop) {
break Some(binop);
}
} else {
continue;
}
}
if let Some(_) = TypeKind::binop_type(&lhs_type, &rhs_type, binop) {
break Some(binop);
}
}; };
let binops = state.scope.binops.filter(&pass::ScopeBinopKey { if let Some(operator) = operator {
params: (lhs_type.clone(), rhs_type.clone()), // Re-typecheck with found operator hints
operator: *op, let (lhs_ty, rhs_ty) = TypeKind::try_collapse_two(
}); (&lhs_type, &rhs_type),
if let Some(binop) = binops (&operator.hands.0, &operator.hands.1),
.iter() )
.filter(|f| f.1.return_ty.narrow_into(&expected_return_ty).is_ok()) .unwrap();
.map(|v| (v.1.clone())) let lhs_res = lhs.typecheck(state, &typerefs, Some(&lhs_ty));
.next() let rhs_res = rhs.typecheck(state, &typerefs, Some(&rhs_ty));
{ state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
lhs.typecheck(state, &typerefs, HintKind::Coerce(binop.hands.0.clone()))?; state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
rhs.typecheck(state, &typerefs, HintKind::Coerce(binop.hands.1.clone()))?; Ok(operator.return_ty.clone())
*ret_ty = binop.narrow(&lhs_type, &rhs_type).unwrap().2;
Ok(ret_ty.clone())
} else { } else {
panic!() // Re-typecheck with typical everyday binop
let lhs_res = lhs.typecheck(
state,
&typerefs,
hint_t.and_then(|t| t.simple_binop_hint(op)).as_ref(),
);
let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
let rhs_res = rhs.typecheck(state, &typerefs, Some(&lhs_type));
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
let both_t = lhs_type.collapse_into(&rhs_type)?;
if *op == BinaryOperator::Minus && !lhs_type.signed() {
if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?)
{
if lhs_val < rhs_val {
return Err(ErrorKind::NegativeUnsignedValue(lhs_type));
}
}
}
if let Some(collapsed) = state.ok(rhs_type.collapse_into(&rhs_type), self.1) {
// Try to coerce both sides again with collapsed type
lhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
rhs.typecheck(state, &typerefs, Some(&collapsed)).ok();
}
both_t
.simple_binop_type(op)
.ok_or(ErrorKind::InvalidBinop(*op, lhs_type, rhs_type))
} }
} }
ExprKind::FunctionCall(function_call) => { ExprKind::FunctionCall(function_call) => {
@ -475,16 +618,21 @@ impl Expression {
.into_iter() .into_iter()
.chain(iter::repeat(TypeKind::Vague(Vague::Unknown))); .chain(iter::repeat(TypeKind::Vague(Vague::Unknown)));
for (param, true_param_t) in function_call.parameters.iter_mut().zip(true_params_iter) { for (param, true_param_t) in
function_call.parameters.iter_mut().zip(true_params_iter)
{
// Typecheck every param separately // Typecheck every param separately
let param_res = param.typecheck(state, &typerefs, HintKind::Coerce(true_param_t.clone())); let param_res = param.typecheck(state, &typerefs, Some(&true_param_t));
let param_t = state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1); let param_t =
state.ok(param_t.narrow_into(&true_param_t), param.1); state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1);
state.ok(param_t.collapse_into(&true_param_t), param.1);
} }
// Make sure function return type is the same as the claimed // Make sure function return type is the same as the claimed
// return type // return type
let ret_t = f.ret.narrow_into(&function_call.return_type.resolve_ref(typerefs))?; let ret_t = f
.ret
.collapse_into(&function_call.return_type.resolve_ref(typerefs))?;
// Update typing to be more accurate // Update typing to be more accurate
function_call.return_type = ret_t.clone(); function_call.return_type = ret_t.clone();
Ok(ret_t.resolve_ref(typerefs)) Ok(ret_t.resolve_ref(typerefs))
@ -493,17 +641,18 @@ impl Expression {
} }
} }
ExprKind::If(IfExpression(cond, lhs, rhs)) => { ExprKind::If(IfExpression(cond, lhs, rhs)) => {
let cond_res = cond.typecheck(state, &typerefs, HintKind::Coerce(TypeKind::Bool)); let cond_res = cond.typecheck(state, &typerefs, Some(&TypeKind::Bool));
let cond_t = state.or_else(cond_res, TypeKind::Vague(Vague::Unknown), cond.1); let cond_t = state.or_else(cond_res, TypeKind::Vague(Vague::Unknown), cond.1);
state.ok(cond_t.narrow_into(&TypeKind::Bool), cond.1); state.ok(cond_t.collapse_into(&TypeKind::Bool), cond.1);
// Typecheck then/else return types and make sure they are the // Typecheck then/else return types and make sure they are the
// same, if else exists. // same, if else exists.
let then_res = lhs.typecheck(state, &typerefs, hint_t.clone()); let then_res = lhs.typecheck(state, &typerefs, hint_t);
let then_ret_t = state.or_else(then_res, TypeKind::Vague(Vague::Unknown), lhs.1); let then_ret_t = state.or_else(then_res, TypeKind::Vague(Vague::Unknown), lhs.1);
let else_ret_t = if let Some(else_expr) = rhs.as_mut() { let else_ret_t = if let Some(else_expr) = rhs.as_mut() {
let res = else_expr.typecheck(state, &typerefs, hint_t.clone()); let res = else_expr.typecheck(state, &typerefs, hint_t);
let else_ret_t = state.or_else(res, TypeKind::Vague(Vague::Unknown), else_expr.1); let else_ret_t =
state.or_else(res, TypeKind::Vague(Vague::Unknown), else_expr.1);
else_ret_t else_ret_t
} else { } else {
@ -514,14 +663,14 @@ impl Expression {
// Make sure then and else -blocks have the same return type // Make sure then and else -blocks have the same return type
let collapsed = then_ret_t let collapsed = then_ret_t
.narrow_into(&else_ret_t) .collapse_into(&else_ret_t)
.or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?; .or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?;
if let Some(rhs) = rhs.as_mut() { if let Some(rhs) = rhs.as_mut() {
// If rhs existed, typecheck both sides to perform type // If rhs existed, typecheck both sides to perform type
// coercion. // coercion.
let lhs_res = lhs.typecheck(state, &typerefs, HintKind::Coerce(collapsed.clone())); let lhs_res = lhs.typecheck(state, &typerefs, Some(&collapsed));
let rhs_res = rhs.typecheck(state, &typerefs, HintKind::Coerce(collapsed.clone())); let rhs_res = rhs.typecheck(state, &typerefs, Some(&collapsed));
state.ok(lhs_res, lhs.1); state.ok(lhs_res, lhs.1);
state.ok(rhs_res, rhs.1); state.ok(rhs_res, rhs.1);
} }
@ -536,13 +685,12 @@ impl Expression {
ExprKind::Indexed(expression, elem_ty, idx_expr) => { ExprKind::Indexed(expression, elem_ty, idx_expr) => {
// Try to unwrap hint type from array if possible // Try to unwrap hint type from array if possible
let hint_t = hint_t.map(|t| match t { let hint_t = hint_t.map(|t| match t {
TypeKind::Array(type_kind, _) => *type_kind.clone(), TypeKind::Array(type_kind, _) => &type_kind,
_ => t.clone(), _ => t,
}); });
// Typecheck and narrow index-expression // Typecheck and narrow index-expression
let idx_expr_res = let idx_expr_res = idx_expr.typecheck(state, typerefs, Some(&TypeKind::U32));
idx_expr.typecheck(state, typerefs, HintKind::Coerce(TypeKind::Vague(VagueType::Integer)));
state.ok(idx_expr_res, idx_expr.1); state.ok(idx_expr_res, idx_expr.1);
// TODO it could be possible to check length against constants.. // TODO it could be possible to check length against constants..
@ -551,7 +699,7 @@ impl Expression {
match expr_t { match expr_t {
TypeKind::Array(inferred_ty, _) | TypeKind::UserPtr(inferred_ty) => { TypeKind::Array(inferred_ty, _) | TypeKind::UserPtr(inferred_ty) => {
let ty = state.or_else( let ty = state.or_else(
elem_ty.resolve_ref(typerefs).narrow_into(&inferred_ty), elem_ty.resolve_ref(typerefs).collapse_into(&inferred_ty),
TypeKind::Vague(Vague::Unknown), TypeKind::Vague(Vague::Unknown),
self.1, self.1,
); );
@ -564,14 +712,14 @@ impl Expression {
ExprKind::Array(expressions) => { ExprKind::Array(expressions) => {
// Try to unwrap hint type from array if possible // Try to unwrap hint type from array if possible
let hint_t = hint_t.map(|t| match t { let hint_t = hint_t.map(|t| match t {
TypeKind::Array(type_kind, _) => *type_kind.clone(), TypeKind::Array(type_kind, _) => &type_kind,
_ => t.clone(), _ => t,
}); });
let mut expr_result = try_all( let mut expr_result = try_all(
expressions expressions
.iter_mut() .iter_mut()
.map(|e| e.typecheck(state, typerefs, hint_t.clone())) .map(|e| e.typecheck(state, typerefs, hint_t))
.collect(), .collect(),
); );
match &mut expr_result { match &mut expr_result {
@ -579,9 +727,12 @@ impl Expression {
let mut iter = expr_types.iter_mut(); let mut iter = expr_types.iter_mut();
if let Some(first) = iter.next() { if let Some(first) = iter.next() {
for other in iter { for other in iter {
state.ok(first.narrow_into(other), self.1); state.ok(first.collapse_into(other), self.1);
} }
Ok(TypeKind::Array(Box::new(first.clone()), expressions.len() as u64)) Ok(TypeKind::Array(
Box::new(first.clone()),
expressions.len() as u64,
))
} else { } else {
Ok(TypeKind::Array(Box::new(TypeKind::Void), 0)) Ok(TypeKind::Array(Box::new(TypeKind::Void), 0))
} }
@ -600,8 +751,9 @@ impl Expression {
let expected_ty = type_kind.resolve_ref(typerefs); let expected_ty = type_kind.resolve_ref(typerefs);
// Typecheck expression // Typecheck expression
let expr_res = expression.typecheck(state, typerefs, HintKind::Coerce(expected_ty.clone())); let expr_res = expression.typecheck(state, typerefs, Some(&expected_ty));
let expr_ty = state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1); let expr_ty =
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
if let TypeKind::CustomType(key) = expr_ty { if let TypeKind::CustomType(key) = expr_ty {
let struct_type = state let struct_type = state
@ -611,7 +763,7 @@ impl Expression {
if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) { if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) {
// Make sure they are the same // Make sure they are the same
let true_ty = state.or_else( let true_ty = state.or_else(
expr_field_ty.narrow_into(&expected_ty), expr_field_ty.collapse_into(&expected_ty),
TypeKind::Vague(Vague::Unknown), TypeKind::Vague(Vague::Unknown),
self.1, self.1,
); );
@ -632,40 +784,27 @@ impl Expression {
.get_struct_type(&type_key) .get_struct_type(&type_key)
.ok_or(ErrorKind::NoSuchType(struct_name.clone(), type_key.1))? .ok_or(ErrorKind::NoSuchType(struct_name.clone(), type_key.1))?
.clone(); .clone();
let mut expected_fields = if let Some(struct_ty) = state.scope.get_struct_type(&type_key) {
struct_ty.0.iter().map(|f| f.0.clone()).collect()
} else {
HashSet::new()
};
for (field_name, field_expr) in items { for (field_name, field_expr) in items {
// Get expected type, or error if field does not exist // Get expected type, or error if field does not exist
let expected_ty = state.or_else( let expected_ty = state.or_else(
struct_def struct_def
.get_field_ty(field_name) .get_field_ty(field_name)
.ok_or(ErrorKind::NoSuchField(format!("{}.{}", struct_name, field_name))), .ok_or(ErrorKind::NoSuchField(format!(
"{}.{}",
struct_name, field_name
))),
&TypeKind::Vague(VagueType::Unknown), &TypeKind::Vague(VagueType::Unknown),
field_expr.1, field_expr.1,
); );
expected_fields.remove(field_name);
// Typecheck the actual expression // Typecheck the actual expression
let expr_res = field_expr.typecheck(state, typerefs, HintKind::Coerce(expected_ty.clone())); let expr_res = field_expr.typecheck(state, typerefs, Some(expected_ty));
let expr_ty = state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1); let expr_ty =
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), field_expr.1);
// Make sure both are the same type, report error if not // Make sure both are the same type, report error if not
state.ok(expr_ty.narrow_into(&expr_ty), field_expr.1); state.ok(expr_ty.collapse_into(&expr_ty), field_expr.1);
} }
state.note_errors(
&expected_fields
.into_iter()
.map(|v| ErrorKind::MissingStructField(v))
.collect(),
self.1,
);
Ok(TypeKind::CustomType(type_key)) Ok(TypeKind::CustomType(type_key))
} }
ExprKind::Borrow(var_ref, mutable) => { ExprKind::Borrow(var_ref, mutable) => {
@ -690,7 +829,7 @@ impl Expression {
// Update typing to be more accurate // Update typing to be more accurate
var_ref.0 = state.or_else( var_ref.0 = state.or_else(
var_ref.0.resolve_ref(typerefs).narrow_into(&existing), var_ref.0.resolve_ref(typerefs).collapse_into(&existing),
TypeKind::Vague(Vague::Unknown), TypeKind::Vague(Vague::Unknown),
var_ref.2, var_ref.2,
); );
@ -714,7 +853,7 @@ impl Expression {
// Update typing to be more accurate // Update typing to be more accurate
let TypeKind::Borrow(inner, mutable) = state.or_else( let TypeKind::Borrow(inner, mutable) = state.or_else(
var_ref.0.resolve_ref(typerefs).narrow_into(&existing), var_ref.0.resolve_ref(typerefs).collapse_into(&existing),
TypeKind::Vague(Vague::Unknown), TypeKind::Vague(Vague::Unknown),
var_ref.2, var_ref.2,
) else { ) else {
@ -726,7 +865,7 @@ impl Expression {
Ok(*inner) Ok(*inner)
} }
ExprKind::CastTo(expression, type_kind) => { ExprKind::CastTo(expression, type_kind) => {
let expr = expression.typecheck(state, typerefs, HintKind::Default)?; let expr = expression.typecheck(state, typerefs, Some(&type_kind))?;
expr.resolve_ref(typerefs).cast_into(type_kind) expr.resolve_ref(typerefs).cast_into(type_kind)
} }
} }
@ -736,11 +875,11 @@ impl Expression {
impl Literal { impl Literal {
/// Try to coerce this literal, ie. convert it to a more specific type in /// Try to coerce this literal, ie. convert it to a more specific type in
/// regards to the given hint if any. /// regards to the given hint if any.
fn try_coerce(self, hint: HintKind) -> Result<Self, ErrorKind> { fn try_coerce(self, hint: Option<TypeKind>) -> Result<Self, ErrorKind> {
use Literal as L; if let Some(hint) = &hint {
use VagueLiteral as VagueL; use Literal as L;
use VagueLiteral as VagueL;
if let HintKind::Coerce(hint) = &hint {
if *hint == self.as_type() { if *hint == self.as_type() {
return Ok(self); return Ok(self);
} }
@ -775,18 +914,38 @@ impl Literal {
(_, TypeKind::Vague(_)) => self, (_, TypeKind::Vague(_)) => self,
_ => Err(ErrorKind::LiteralIncompatible(self, hint.clone()))?, _ => Err(ErrorKind::LiteralIncompatible(self, hint.clone()))?,
}) })
} else if hint == HintKind::Default {
match self {
Literal::Vague(vague) => match vague {
VagueLiteral::Number(val) => Ok(L::I32(val as i32)),
VagueLiteral::Decimal(val) => Ok(L::F32(val as f32)),
},
_ => Ok(self),
}
} else { } else {
Ok(self) Ok(self)
} }
} }
} }
impl TypeKind {} impl TypeKind {
fn assert_known(
&self,
refs: &TypeRefs,
state: &TypecheckPassState,
) -> Result<TypeKind, ErrorKind> {
self.is_known(refs, state).map(|_| self.clone())
}
fn is_known(&self, refs: &TypeRefs, state: &TypecheckPassState) -> Result<(), ErrorKind> {
match &self {
TypeKind::Array(type_kind, _) => type_kind.as_ref().is_known(refs, state),
TypeKind::CustomType(custom_type_key) => state
.scope
.types
.get(custom_type_key)
.map(|_| ())
.ok_or(ErrorKind::NoSuchType(
custom_type_key.0.clone(),
state.module_id.unwrap(),
)),
TypeKind::Borrow(type_kind, _) => type_kind.is_known(refs, state),
TypeKind::UserPtr(type_kind) => type_kind.is_known(refs, state),
TypeKind::CodegenPtr(type_kind) => type_kind.is_known(refs, state),
TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(*vague_type)),
_ => Ok(()),
}
}
}

View File

@ -1,318 +0,0 @@
use crate::mir::VagueType as Vague;
use crate::mir::*;
use typecheck::ErrorTypedefKind;
use typerefs::TypeRefs;
use super::implement::{NumValueError, TypeCategory};
use super::pass::PassState;
pub mod typecheck;
pub mod typeinference;
pub mod typerefs;
pub type TypecheckPassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)]
pub enum ErrorKind {
#[error("NULL error, should never occur!")]
Null,
#[error("Type is vague: {0}")]
TypeIsVague(VagueType),
#[error("Literal {0} can not be coerced to type {1}")]
LiteralIncompatible(Literal, TypeKind),
#[error("Types {0} and {1} are incompatible")]
TypesIncompatible(TypeKind, TypeKind),
#[error("Variable not defined: {0}")]
VariableNotDefined(String),
#[error("Function not defined: {0}")]
FunctionNotDefined(String),
#[error("Expected a return type of {0}, got {1} instead")]
ReturnTypeMismatch(TypeKind, TypeKind),
#[error("Function {0} already defined {1}")]
FunctionAlreadyDefined(String, ErrorTypedefKind),
#[error("Variable already defined: {0}")]
VariableAlreadyDefined(String),
#[error("Variable {0} is not declared as mutable")]
VariableNotMutable(String),
#[error("Function {0} was given {1} parameters, but {2} were expected")]
InvalidAmountParameters(String, usize, usize),
#[error("Unable to infer type {0}")]
TypeNotInferrable(TypeKind),
#[error("Expected branch type to be {0}, found {1} instead")]
BranchTypesDiffer(TypeKind, TypeKind),
#[error("Attempted to index a non-indexable type of {0}")]
TriedIndexingNonIndexable(TypeKind),
#[error("Index {0} out of bounds ({1})")]
IndexOutOfBounds(u64, u64),
#[error("No such type {0} could be found in module {1}")]
NoSuchType(String, SourceModuleId),
#[error("Attempted to access field of non-struct type of {0}")]
TriedAccessingNonStruct(TypeKind),
#[error("No such struct-field on type {0}")]
NoSuchField(String),
#[error("Missing definition for field \"{0}\"")]
MissingStructField(String),
#[error("Struct field declared twice {0}")]
DuplicateStructField(String),
#[error("Type declared twice {0}")]
DuplicateTypeName(String),
#[error("Recursive type definition: {0}.{1}")]
RecursiveTypeDefinition(String, String),
#[error("This type of expression can not be used for assignment")]
InvalidSetExpression,
#[error("Can not deref {0}, as it is not a borrow")]
AttemptedDerefNonBorrow(String),
#[error("Types {0} and {1} differ in mutability")]
TypesDifferMutability(TypeKind, TypeKind),
#[error("Cannot mutably borrow variable {0}, which is not declared as mutable")]
ImpossibleMutableBorrow(String),
#[error("Cannot declare variable {0} as mutable, when it's type is immutable")]
ImpossibleMutLet(String),
#[error("Cannot produce a negative unsigned value of type {0}")]
NegativeUnsignedValue(TypeKind),
#[error("Cannot cast type {0} into type {1}")]
NotCastableTo(TypeKind, TypeKind),
#[error(transparent)]
NumValueError(#[from] NumValueError),
#[error("Binary operation {0} between {1} and {2} is already defined")]
BinaryOpAlreadyDefined(BinaryOperator, TypeKind, TypeKind),
#[error("Binary operation {0} between {1} and {2} is not defined")]
InvalidBinop(BinaryOperator, TypeKind, TypeKind),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum HintKind {
Coerce(TypeKind),
Default,
None,
}
impl HintKind {
pub fn map<T>(&self, fun: T) -> HintKind
where
T: FnOnce(&TypeKind) -> TypeKind,
{
match self {
HintKind::Coerce(type_kind) => HintKind::Coerce(fun(type_kind)),
_ => self.clone(),
}
}
}
impl From<Option<TypeKind>> for HintKind {
fn from(value: Option<TypeKind>) -> Self {
match value {
Some(ty) => HintKind::Coerce(ty),
None => HintKind::None,
}
}
}
impl TypeKind {
pub(super) fn narrow_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
if self == other {
return Ok(self.clone());
}
match (self, other) {
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => match other {
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Integer)),
TypeKind::Vague(Vague::Integer) => Ok(TypeKind::Vague(Vague::Integer)),
TypeKind::I8
| TypeKind::I16
| TypeKind::I32
| TypeKind::I64
| TypeKind::I128
| TypeKind::U8
| TypeKind::U16
| TypeKind::U32
| TypeKind::U64
| TypeKind::U128 => Ok(other.clone()),
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
},
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => match other {
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)),
TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)),
TypeKind::F16
| TypeKind::F32B
| TypeKind::F32
| TypeKind::F64
| TypeKind::F80
| TypeKind::F128
| TypeKind::F128PPC => Ok(other.clone()),
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
},
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => Ok(other.clone()),
(TypeKind::Borrow(val1, mut1), TypeKind::Borrow(val2, mut2)) => {
// Extracted to give priority for other collapse-error
let collapsed = val1.narrow_into(val2)?;
if mut1 == mut2 {
Ok(TypeKind::Borrow(Box::new(collapsed), *mut1 && *mut2))
} else {
Err(ErrorKind::TypesDifferMutability(self.clone(), other.clone()))
}
}
(TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => {
Ok(TypeKind::UserPtr(Box::new(val1.narrow_into(val2)?)))
}
(TypeKind::Array(val1, len1), TypeKind::Array(val2, len2)) => {
if len1 != len2 {
return Err(ErrorKind::TypesIncompatible(self.clone(), other.clone()));
}
Ok(TypeKind::Array(Box::new(val1.narrow_into(val2)?), *len1))
}
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
}
}
pub(super) fn widen_into(&self, other: &TypeKind) -> TypeKind {
if self == other {
return self.clone();
}
match (self, other) {
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => {
TypeKind::Vague(VagueType::Unknown)
}
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => match other {
TypeKind::I8
| TypeKind::I16
| TypeKind::I32
| TypeKind::I64
| TypeKind::I128
| TypeKind::U8
| TypeKind::U16
| TypeKind::U32
| TypeKind::U64
| TypeKind::U128 => TypeKind::Vague(VagueType::Integer),
_ => TypeKind::Vague(VagueType::Unknown),
},
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => match other {
TypeKind::F16
| TypeKind::F32B
| TypeKind::F32
| TypeKind::F64
| TypeKind::F80
| TypeKind::F128
| TypeKind::F128PPC => TypeKind::Vague(VagueType::Decimal),
_ => TypeKind::Vague(VagueType::Unknown),
},
(TypeKind::UserPtr(val1), TypeKind::UserPtr(val2)) => TypeKind::UserPtr(Box::new(val1.widen_into(val2))),
(TypeKind::CodegenPtr(val1), TypeKind::CodegenPtr(val2)) => {
TypeKind::CodegenPtr(Box::new(val1.widen_into(val2)))
}
(TypeKind::Array(val1, len1), TypeKind::Array(val2, len2)) => {
if len1 == len2 {
TypeKind::Array(Box::new(val1.widen_into(val2)), *len1)
} else {
TypeKind::Vague(VagueType::Unknown)
}
}
(TypeKind::Borrow(val1, mutable1), TypeKind::Borrow(val2, mutable2)) => {
if mutable1 == mutable2 {
TypeKind::Borrow(Box::new(val1.widen_into(val2)), *mutable1)
} else {
TypeKind::Vague(VagueType::Unknown)
}
}
_ => {
if self.category() == other.category() {
match self.category() {
TypeCategory::Integer => TypeKind::Vague(VagueType::Integer),
TypeCategory::Real => TypeKind::Vague(VagueType::Decimal),
TypeCategory::Bool => TypeKind::Bool,
_ => TypeKind::Vague(VagueType::Unknown),
}
} else {
TypeKind::Vague(VagueType::Unknown)
}
}
}
}
pub(super) fn cast_into(&self, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
if let Ok(collapsed) = self.narrow_into(other) {
Ok(collapsed)
} else {
let self_cat = self.category();
let other_cat = other.category();
match (self, other) {
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Ok(other.clone()),
(TypeKind::Char, TypeKind::U8) => Ok(other.clone()),
(TypeKind::U8, TypeKind::Char) => Ok(other.clone()),
_ => match (&self_cat, &other_cat) {
(TypeCategory::Integer, TypeCategory::Integer) => Ok(other.clone()),
(TypeCategory::Integer, TypeCategory::Real) => Ok(other.clone()),
(TypeCategory::Real, TypeCategory::Integer) => Ok(other.clone()),
(TypeCategory::Real, TypeCategory::Real) => Ok(other.clone()),
_ => Err(ErrorKind::NotCastableTo(self.clone(), other.clone())),
},
}
}
}
/// Assert that a type is already known and not vague. Return said type or
/// error.
pub(super) fn assert_unvague(&self) -> Result<TypeKind, ErrorKind> {
self.known().map_err(ErrorKind::TypeIsVague)
}
/// Try to collapse a type on itself producing a default type if one exists,
/// Error if not.
pub(super) fn or_default(&self) -> Result<TypeKind, ErrorKind> {
Ok(match self {
TypeKind::Vague(vague_type) => match &vague_type {
Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type))?,
Vague::Integer => TypeKind::I32,
Vague::TypeRef(_) => panic!("Hinted default!"),
VagueType::Decimal => TypeKind::F32,
},
TypeKind::Array(type_kind, len) => TypeKind::Array(Box::new(type_kind.or_default()?), *len),
TypeKind::Borrow(type_kind, mutable) => TypeKind::Borrow(Box::new(type_kind.or_default()?), *mutable),
TypeKind::UserPtr(type_kind) => TypeKind::UserPtr(Box::new(type_kind.or_default()?)),
TypeKind::CodegenPtr(type_kind) => TypeKind::CodegenPtr(Box::new(type_kind.or_default()?)),
_ => self.clone(),
})
}
pub(super) fn resolve_weak(&self, refs: &TypeRefs) -> TypeKind {
match self {
TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_wide_type(*idx).unwrap(),
_ => self.clone(),
}
}
pub(super) fn resolve_ref(&self, refs: &TypeRefs) -> TypeKind {
let resolved = self.resolve_weak(refs);
match resolved {
TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_ref(refs)), len),
TypeKind::Borrow(inner, mutable) => TypeKind::Borrow(Box::new(inner.resolve_ref(refs)), mutable),
_ => resolved,
}
}
pub(super) fn assert_known(&self, refs: &TypeRefs, state: &TypecheckPassState) -> Result<TypeKind, ErrorKind> {
self.is_known(refs, state).map(|_| self.clone())
}
pub(super) fn is_known(&self, refs: &TypeRefs, state: &TypecheckPassState) -> Result<(), ErrorKind> {
match &self {
TypeKind::Array(type_kind, _) => type_kind.as_ref().is_known(refs, state),
TypeKind::CustomType(custom_type_key) => {
state
.scope
.types
.get(custom_type_key)
.map(|_| ())
.ok_or(ErrorKind::NoSuchType(
custom_type_key.0.clone(),
state.module_id.unwrap(),
))
}
TypeKind::Borrow(type_kind, _) => type_kind.is_known(refs, state),
TypeKind::UserPtr(type_kind) => type_kind.is_known(refs, state),
TypeKind::CodegenPtr(type_kind) => type_kind.is_known(refs, state),
TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(*vague_type)),
_ => Ok(()),
}
}
}

View File

@ -1,404 +0,0 @@
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
rc::Rc,
};
use crate::{
ast::BinopDefinition,
mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType},
};
use super::{
super::pass::{ScopeBinopDef, ScopeBinopKey, Storage},
ErrorKind,
};
#[derive(Clone)]
pub struct TypeRef<'scope>(pub(super) TypeIdRef, pub(super) &'scope ScopeTypeRefs<'scope>);
impl<'scope> TypeRef<'scope> {
/// Resolve current type in a weak manner, not resolving any Arrays or
/// further inner types
pub fn resolve_weak(&self) -> Option<TypeKind> {
Some(self.1.types.retrieve_wide_type(*self.0.borrow())?)
}
/// Resolve type deeply, trying to resolve any inner types as well.
pub fn resolve_deep(&self) -> Option<TypeKind> {
let resolved = self.resolve_weak()?;
match resolved {
TypeKind::Array(elem_ty, len) => {
let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_weak()?;
Some(TypeKind::Array(Box::new(resolved_elem_ty), len))
}
_ => Some(resolved),
}
}
pub fn narrow(&mut self, other: &TypeRef) -> Option<TypeRef<'scope>> {
self.1.combine_vars(self, other)
}
pub fn as_type(&self) -> TypeKind {
TypeKind::Vague(VagueType::TypeRef(*self.0.borrow()))
}
}
impl<'scope> std::fmt::Debug for TypeRef<'scope> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Hint")
.field(&self.0)
.field(&self.resolve_deep().unwrap())
.finish()
}
}
type TypeIdRef = Rc<RefCell<usize>>;
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
pub enum TypeRefKind {
Direct(TypeKind),
BinOp(BinaryOperator, TypeKind, TypeKind),
}
impl TypeRefKind {
pub fn widen(&self, types: &TypeRefs) -> TypeKind {
match self {
TypeRefKind::BinOp(op, lhs, rhs) => {
let mut binops = types
.binop_types
.iter()
.filter(|b| b.1.operator == *op)
.map(|b| {
b.1.narrow(&lhs.resolve_ref(types), &rhs.resolve_ref(types))
.map(|b| b.2)
})
.filter_map(|s| s);
if let Some(mut ty) = binops.next() {
while let Some(other) = binops.next() {
ty = ty.widen_into(&other);
}
ty
} else {
TypeKind::Vague(VagueType::Unknown)
}
}
TypeRefKind::Direct(ty) => match ty {
TypeKind::Vague(VagueType::TypeRef(id)) => types.retrieve_wide_type(*id).unwrap(),
_ => ty.clone(),
},
}
}
}
#[derive(Default, Debug)]
pub struct TypeRefs {
/// Simple list of types that variables can refrence
pub(super) hints: RefCell<Vec<TypeRefKind>>,
/// Indirect ID-references, referring to hints-vec
pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
pub(super) binop_types: BinopMap,
}
impl std::fmt::Display for TypeRefs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (i, typeref) in self.type_refs.borrow().iter().enumerate() {
let idx = *typeref.borrow();
writeln!(
f,
"{:<3} = {:<3} = {:?} = {:?}",
i,
unsafe { *self.recurse_type_ref(idx).borrow() },
self.retrieve_typeref(idx),
self.retrieve_wide_type(idx),
)?;
}
Ok(())
}
}
impl TypeRefs {
pub fn with_binops(binops: BinopMap) -> TypeRefs {
TypeRefs {
hints: Default::default(),
type_refs: Default::default(),
binop_types: binops,
}
}
pub fn new(&self, ty: &TypeKind) -> TypeIdRef {
let idx = self.hints.borrow().len();
let typecell = Rc::new(RefCell::new(idx));
self.type_refs.borrow_mut().push(typecell.clone());
self.hints.borrow_mut().push(TypeRefKind::Direct(ty.clone()));
typecell
}
pub fn binop(&self, op: BinaryOperator, lhs: &TypeRef, rhs: &TypeRef) -> TypeIdRef {
let idx = self.hints.borrow().len();
let typecell = Rc::new(RefCell::new(idx));
self.type_refs.borrow_mut().push(typecell.clone());
self.hints
.borrow_mut()
.push(TypeRefKind::BinOp(op, lhs.as_type(), rhs.as_type()));
typecell
}
pub fn find(&self, ty: &TypeKind) -> Option<TypeIdRef> {
if ty.known().is_err() {
// Only do this for non-vague types that can not be further narrowed
// down.
return None;
}
if let Some(idx) = self
.hints
.borrow_mut()
.iter()
.enumerate()
.find(|(_, t)| t == &&TypeRefKind::Direct(ty.clone()))
.map(|(i, _)| i)
{
Some(Rc::new(RefCell::new(idx)))
} else {
None
}
}
pub(super) unsafe fn recurse_type_ref(&self, mut idx: usize) -> TypeIdRef {
let refs = self.type_refs.borrow();
let mut inner_idx = refs.get_unchecked(idx);
let mut seen = HashSet::new();
while (*inner_idx.borrow()) != idx && !seen.contains(&idx) {
seen.insert(idx);
idx = *inner_idx.borrow();
inner_idx = refs.get_unchecked(idx);
}
return refs.get_unchecked(idx).clone();
}
pub fn retrieve_typeref(&self, idx: usize) -> Option<TypeRefKind> {
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
self.hints.borrow().get(inner_idx).cloned()
}
pub fn retrieve_wide_type(&self, idx: usize) -> Option<TypeKind> {
self.retrieve_typeref(idx).map(|t| t.widen(self))
}
}
#[derive(Debug)]
pub struct ScopeTypeRefs<'outer> {
pub types: &'outer TypeRefs,
outer: Option<&'outer ScopeTypeRefs<'outer>>,
/// Mapping of what types variables point to
variables: RefCell<HashMap<String, (bool, TypeIdRef)>>,
}
impl<'outer> ScopeTypeRefs<'outer> {
pub fn from(types: &'outer TypeRefs) -> ScopeTypeRefs<'outer> {
ScopeTypeRefs {
types,
outer: Default::default(),
variables: Default::default(),
}
}
pub fn new_var(
&'outer self,
name: String,
mutable: bool,
initial_ty: &TypeKind,
) -> Result<TypeRef<'outer>, ErrorKind> {
if self.variables.borrow().contains_key(&name) {
return Err(ErrorKind::VariableAlreadyDefined(name));
}
let type_ref = self.from_type(&initial_ty).unwrap();
self.variables.borrow_mut().insert(name, (mutable, type_ref.0.clone()));
Ok(type_ref)
}
pub fn from_type(&'outer self, ty: &TypeKind) -> Option<TypeRef<'outer>> {
let idx = match ty {
TypeKind::Vague(VagueType::TypeRef(idx)) => {
let inner_idx = unsafe { *self.types.recurse_type_ref(*idx).borrow() };
self.types.type_refs.borrow().get(inner_idx).cloned()?
}
TypeKind::Vague(_) => self.types.new(ty),
TypeKind::Array(elem_ty, length) => {
let elem_ty = self.from_type(elem_ty)?;
self.types.new(&TypeKind::Array(Box::new(elem_ty.as_type()), *length))
}
TypeKind::Borrow(ty, mutable) => {
let inner_ty = self.from_type(ty)?;
self.types
.new(&&TypeKind::Borrow(Box::new(inner_ty.as_type()), *mutable))
}
_ => {
if let Some(ty_ref) = self.types.find(ty) {
ty_ref
} else {
self.types.new(ty)
}
}
};
Some(TypeRef(idx, self))
}
pub fn from_binop(&'outer self, op: BinaryOperator, lhs: &TypeRef, rhs: &TypeRef) -> TypeRef<'outer> {
TypeRef(self.types.binop(op, lhs, rhs), self)
}
fn narrow_to_type(&'outer self, hint: &TypeRef, ty: &TypeKind) -> Option<TypeRef<'outer>> {
unsafe {
let mut hints = self.types.hints.borrow_mut();
let existing = hints.get_unchecked_mut(*hint.0.borrow());
match existing {
TypeRefKind::Direct(type_kind) => {
*type_kind = type_kind.narrow_into(&ty).ok()?;
}
TypeRefKind::BinOp(op, lhs, rhs) => {
let op = op.clone();
let lhs = lhs.clone();
let rhs = rhs.clone();
drop(hints);
let lhs_resolved = lhs.resolve_ref(self.types);
let rhs_resolved = rhs.resolve_ref(self.types);
let binops = self
.types
.binop_types
.iter()
.filter(|b| b.1.operator == op && b.1.return_ty == *ty)
.collect::<Vec<_>>();
for binop in binops {
if let (Ok(lhs_narrow), Ok(rhs_narrow)) = (
lhs_resolved.narrow_into(&binop.1.hands.0),
rhs_resolved.narrow_into(&binop.1.hands.1),
) {
match &lhs {
TypeKind::Vague(VagueType::TypeRef(idx)) => {
let mut lhs_ref = TypeRef(Rc::new(RefCell::new(*idx)), self);
self.narrow_to_type(&mut lhs_ref, &lhs_narrow).unwrap_or(lhs_ref);
}
_ => {}
};
match &rhs {
TypeKind::Vague(VagueType::TypeRef(idx)) => {
let mut rhs_ref = TypeRef(Rc::new(RefCell::new(*idx)), self);
self.narrow_to_type(&mut rhs_ref, &rhs_narrow).unwrap_or(rhs_ref);
}
_ => {}
}
}
}
}
}
Some(TypeRef(hint.0.clone(), self))
}
}
pub fn try_default_deep(&self, ty: &TypeKind) -> Option<TypeKind> {
Some(match &ty {
TypeKind::Array(type_kind, _) => self.try_default_deep(type_kind)?,
TypeKind::CustomType(_) => ty.clone(),
TypeKind::Borrow(type_kind, _) => self.try_default_deep(type_kind)?,
TypeKind::UserPtr(type_kind) => self.try_default_deep(type_kind)?,
TypeKind::CodegenPtr(type_kind) => self.try_default_deep(type_kind)?,
TypeKind::Vague(vague_type) => match vague_type {
VagueType::Unknown => ty.clone(),
VagueType::Integer => ty.or_default().unwrap(),
VagueType::Decimal => ty.or_default().unwrap(),
VagueType::TypeRef(idx) => {
let typeref = TypeRef(Rc::new(RefCell::new(*idx)), self);
self.narrow_to_type(&typeref, &self.try_default_deep(&typeref.resolve_deep()?)?)?
.resolve_deep()?
}
},
_ => ty.clone(),
})
}
fn combine_vars(&'outer self, hint1: &TypeRef, hint2: &TypeRef) -> Option<TypeRef<'outer>> {
unsafe {
let ty = self
.types
.hints
.borrow()
.get_unchecked(*hint2.0.borrow())
.clone()
.widen(self.types);
self.narrow_to_type(&hint1, &ty)?;
let hint1_typeref = self.types.retrieve_typeref(*hint1.0.borrow()).unwrap();
for idx in self.types.type_refs.borrow_mut().iter_mut() {
match hint1_typeref {
TypeRefKind::Direct(_) => {
if *idx == hint2.0 && idx != &hint1.0 {
*idx.borrow_mut() = *hint1.0.borrow();
}
}
TypeRefKind::BinOp(_, _, _) => {
// TODO may not be good ?
// if *idx == hint2.0 && idx != &hint1.0 {
// *idx.borrow_mut() = *hint1.0.borrow();
// }
}
}
}
Some(TypeRef(hint1.0.clone(), self))
}
}
pub fn inner(&'outer self) -> ScopeTypeRefs<'outer> {
ScopeTypeRefs {
types: self.types,
outer: Some(self),
variables: Default::default(),
}
}
pub fn find_var(&'outer self, name: &String) -> Option<(bool, TypeRef<'outer>)> {
self.variables
.borrow()
.get(name)
.map(|(mutable, idx)| (*mutable, TypeRef(idx.clone(), self)))
.or(self.outer.map(|o| o.find_var(name)).flatten())
}
pub fn available_binops(
&'outer self,
op: &BinaryOperator,
lhs: &mut TypeRef<'outer>,
rhs: &mut TypeRef<'outer>,
) -> Vec<ScopeBinopDef> {
let mut applying_binops = Vec::new();
for (_, binop) in self.types.binop_types.iter() {
if binop.operator != *op {
continue;
}
if let Some(_) = check_binop(lhs, rhs, binop) {
applying_binops.push(binop.clone());
continue;
}
if binop.operator.is_commutative() {
if let Some(_) = check_binop(lhs, rhs, binop) {
applying_binops.push(binop.clone());
continue;
}
}
}
applying_binops
}
}
fn check_binop<'o>(
lhs: &mut TypeRef<'o>,
rhs: &mut TypeRef<'o>,
binop: &ScopeBinopDef,
) -> Option<(TypeKind, TypeKind, TypeKind)> {
binop.narrow(&lhs.resolve_deep()?, &rhs.resolve_deep()?)
}

View File

@ -10,23 +10,17 @@ use std::{
iter, iter,
}; };
use crate::{ use crate::{mir::TypeKind, util::try_all};
mir::{
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
},
util::try_all,
};
use super::{ use super::{
super::{ pass::{Pass, PassResult, PassState, ScopeBinopKey},
pass::{Pass, PassResult, PassState, ScopeBinopKey}, typecheck::{ErrorKind, ErrorTypedefKind},
TypeKind::*,
VagueType::*,
},
typecheck::ErrorTypedefKind,
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs}, typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
ErrorKind, TypecheckPassState, BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition,
FunctionDefinitionKind, IfExpression, Module, ReturnKind, StmtKind,
TypeKind::*,
VagueType::*,
WhileStatement,
}; };
/// Struct used to implement Type Inference, where an intermediary /// Struct used to implement Type Inference, where an intermediary
@ -36,16 +30,21 @@ pub struct TypeInference<'t> {
pub refs: &'t TypeRefs, pub refs: &'t TypeRefs,
} }
type TypeInferencePassState<'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
impl<'t> Pass for TypeInference<'t> { impl<'t> Pass for TypeInference<'t> {
type Data = (); type Data = ();
type TError = ErrorKind; type TError = ErrorKind;
fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) -> PassResult { fn module(&mut self, module: &mut Module, mut state: TypeInferencePassState) -> PassResult {
let mut seen_functions = HashMap::new(); let mut seen_functions = HashMap::new();
for function in &mut module.functions { for function in &mut module.functions {
if let Some(kind) = seen_functions.get(&function.name) { if let Some(kind) = seen_functions.get(&function.name) {
state.note_errors( state.note_errors(
&vec![ErrorKind::FunctionAlreadyDefined(function.name.clone(), *kind)], &vec![ErrorKind::FunctionAlreadyDefined(
function.name.clone(),
*kind,
)],
function.signature(), function.signature(),
); );
} else { } else {
@ -66,7 +65,8 @@ impl<'t> Pass for TypeInference<'t> {
params: (binop.lhs.1.clone(), binop.rhs.1.clone()), params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
operator: binop.op, operator: binop.op,
}; };
if seen_binops.contains(&binop_key) || (binop.lhs == binop.rhs && binop.lhs.1.category().is_simple_maths()) if seen_binops.contains(&binop_key)
|| (binop.lhs == binop.rhs && binop.lhs.1.category().is_simple_maths())
{ {
state.note_errors( state.note_errors(
&vec![ErrorKind::BinaryOpAlreadyDefined( &vec![ErrorKind::BinaryOpAlreadyDefined(
@ -95,10 +95,18 @@ impl<'t> Pass for TypeInference<'t> {
} }
impl BinopDefinition { impl BinopDefinition {
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> { fn infer_types(
&mut self,
type_refs: &TypeRefs,
state: &mut TypeInferencePassState,
) -> Result<(), ErrorKind> {
let scope_hints = ScopeTypeRefs::from(type_refs); let scope_hints = ScopeTypeRefs::from(type_refs);
let lhs_ty = state.or_else(self.lhs.1.assert_unvague(), Vague(Unknown), self.signature()); let lhs_ty = state.or_else(
self.lhs.1.assert_unvague(),
Vague(Unknown),
self.signature(),
);
state.ok( state.ok(
scope_hints scope_hints
.new_var(self.lhs.0.clone(), false, &lhs_ty) .new_var(self.lhs.0.clone(), false, &lhs_ty)
@ -106,7 +114,11 @@ impl BinopDefinition {
self.signature(), self.signature(),
); );
let rhs_ty = state.or_else(self.rhs.1.assert_unvague(), Vague(Unknown), self.signature()); let rhs_ty = state.or_else(
self.rhs.1.assert_unvague(),
Vague(Unknown),
self.signature(),
);
state.ok( state.ok(
scope_hints scope_hints
@ -115,11 +127,10 @@ impl BinopDefinition {
self.signature(), self.signature(),
); );
let ret_ty = self let ret_ty =
.fn_kind self.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());
} }
@ -128,7 +139,11 @@ impl BinopDefinition {
} }
impl FunctionDefinition { impl FunctionDefinition {
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> { fn infer_types(
&mut self,
type_refs: &TypeRefs,
state: &mut TypeInferencePassState,
) -> Result<(), ErrorKind> {
let scope_refs = ScopeTypeRefs::from(type_refs); let scope_refs = ScopeTypeRefs::from(type_refs);
for param in &self.parameters { for param in &self.parameters {
let param_t = state.or_else(param.1.assert_unvague(), Vague(Unknown), self.signature()); let param_t = state.or_else(param.1.assert_unvague(), Vague(Unknown), self.signature());
@ -168,7 +183,7 @@ impl FunctionDefinition {
impl FunctionDefinitionKind { impl FunctionDefinitionKind {
fn infer_types<'s>( fn infer_types<'s>(
&mut self, &mut self,
state: &mut TypecheckPassState, state: &mut TypeInferencePassState,
scope_refs: &'s ScopeTypeRefs, scope_refs: &'s ScopeTypeRefs,
hint: Option<TypeKind>, hint: Option<TypeKind>,
) -> Result<Option<TypeRef<'s>>, ErrorKind> { ) -> Result<Option<TypeRef<'s>>, ErrorKind> {
@ -191,20 +206,18 @@ impl FunctionDefinitionKind {
impl Block { impl Block {
fn infer_types<'s>( fn infer_types<'s>(
&mut self, &mut self,
state: &mut TypecheckPassState, state: &mut TypeInferencePassState,
outer_refs: &'s ScopeTypeRefs, outer_refs: &'s ScopeTypeRefs,
) -> Result<(ReturnKind, TypeRef<'s>), ErrorKind> { ) -> Result<(ReturnKind, TypeRef<'s>), ErrorKind> {
let mut state = state.inner(); let mut state = state.inner();
let inner_refs = outer_refs.inner(); let inner_refs = outer_refs.inner();
// Keep track of variables created in this scope
let mut scope_variables = Vec::new();
for statement in &mut self.statements { for statement in &mut self.statements {
match &mut statement.0 { match &mut statement.0 {
StmtKind::Let(var, mutable, expr) => { StmtKind::Let(var, mutable, expr) => {
// Get the TypeRef for this variable declaration // Get the TypeRef for this variable declaration
let mut var_ref = state.ok(inner_refs.new_var(var.1.clone(), *mutable, &var.0), var.2); let mut var_ref =
state.ok(inner_refs.new_var(var.1.clone(), *mutable, &var.0), var.2);
// If ok, update the MIR type to this TypeRef // If ok, update the MIR type to this TypeRef
if let Some(var_ref) = &var_ref { if let Some(var_ref) = &var_ref {
@ -217,12 +230,11 @@ impl Block {
// Try to narrow the variable type declaration with the // Try to narrow the variable type declaration with the
// expression // expression
if let (Some(var_ref), Some(expr_ty_ref)) = (var_ref.as_mut(), expr_ty_ref.as_mut()) { if let (Some(var_ref), Some(expr_ty_ref)) =
(var_ref.as_mut(), expr_ty_ref.as_mut())
{
var_ref.narrow(&expr_ty_ref); var_ref.narrow(&expr_ty_ref);
} }
// Add variable to list of tracked variables
scope_variables.push(var.clone());
} }
StmtKind::Set(lhs, rhs) => { StmtKind::Set(lhs, rhs) => {
// Infer hints for the expression itself // Infer hints for the expression itself
@ -243,7 +255,9 @@ impl Block {
let expr_res = expr.infer_types(&mut state, &inner_refs); let expr_res = expr.infer_types(&mut state, &inner_refs);
state.ok(expr_res, expr.1); state.ok(expr_res, expr.1);
} }
StmtKind::While(WhileStatement { condition, block, .. }) => { StmtKind::While(WhileStatement {
condition, block, ..
}) => {
condition.infer_types(&mut state, &inner_refs)?; condition.infer_types(&mut state, &inner_refs)?;
block.infer_types(&mut state, &inner_refs)?; block.infer_types(&mut state, &inner_refs)?;
} }
@ -272,12 +286,6 @@ impl Block {
} }
} }
// if variables aren't known at this time, they will never be. Default
// their types.
for variable in scope_variables {
inner_refs.try_default_deep(&variable.0);
}
Ok((kind, ret_type_ref)) Ok((kind, ret_type_ref))
} }
} }
@ -285,7 +293,7 @@ impl Block {
impl Expression { impl Expression {
fn infer_types<'s>( fn infer_types<'s>(
&mut self, &mut self,
state: &mut TypecheckPassState, state: &mut TypeInferencePassState,
type_refs: &'s ScopeTypeRefs<'s>, type_refs: &'s ScopeTypeRefs<'s>,
) -> Result<TypeRef<'s>, ErrorKind> { ) -> Result<TypeRef<'s>, ErrorKind> {
match &mut self.0 { match &mut self.0 {
@ -304,52 +312,42 @@ impl Expression {
type_ref type_ref
} }
ExprKind::Literal(literal) => Ok(type_refs.from_type(&literal.as_type()).unwrap()), ExprKind::Literal(literal) => Ok(type_refs.from_type(&literal.as_type()).unwrap()),
ExprKind::BinOp(op, lhs, rhs, return_ty) => { ExprKind::BinOp(op, lhs, rhs) => {
// Infer LHS and RHS, and return binop type // Infer LHS and RHS, and return binop type
let mut lhs_ref = lhs.infer_types(state, type_refs)?; let mut lhs_ref = lhs.infer_types(state, type_refs)?;
let mut rhs_ref = rhs.infer_types(state, type_refs)?; let mut rhs_ref = rhs.infer_types(state, type_refs)?;
let binops = if let (Some(lhs_ty), Some(rhs_ty)) = (lhs_ref.resolve_deep(), rhs_ref.resolve_deep()) { if let Ok(binop) = type_refs
let mut applying_binops = Vec::new(); .binop(op, &mut lhs_ref, &mut rhs_ref, &state.scope.binops)
for (_, binop) in state.scope.binops.iter() { .ok_or(ErrorKind::TypesIncompatible(
if binop.operator != *op {
continue;
}
if let Some(_) = binop.narrow(&lhs_ty, &rhs_ty) {
applying_binops.push(binop.clone());
continue;
}
if binop.operator.is_commutative() {
if let Some(_) = binop.narrow(&lhs_ty, &rhs_ty) {
applying_binops.push(binop.clone());
continue;
}
}
}
applying_binops
} else {
Vec::new()
};
if binops.len() > 0 {
let binop = unsafe { binops.get_unchecked(0) };
let mut widened_lhs = binop.hands.0.clone();
let mut widened_rhs = binop.hands.1.clone();
for binop in binops.iter().skip(1) {
widened_lhs = widened_lhs.widen_into(&binop.hands.0);
widened_rhs = widened_rhs.widen_into(&binop.hands.1);
}
let binop_res = type_refs.from_binop(*op, &lhs_ref, &rhs_ref);
lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap());
rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap());
*return_ty = binop_res.as_type();
Ok(binop_res)
} else {
Err(ErrorKind::InvalidBinop(
*op,
lhs_ref.resolve_deep().unwrap(), lhs_ref.resolve_deep().unwrap(),
rhs_ref.resolve_deep().unwrap(), rhs_ref.resolve_deep().unwrap(),
)) ))
{
Ok(binop)
} else {
let typeref = state.or_else(
lhs_ref.narrow(&rhs_ref).ok_or(ErrorKind::InvalidBinop(
*op,
lhs_ref.resolve_deep().unwrap(),
rhs_ref.resolve_deep().unwrap(),
)),
type_refs.from_type(&Vague(Unknown)).unwrap(),
self.1,
);
Ok(type_refs
.from_type(
&typeref
.resolve_deep()
.unwrap()
.simple_binop_type(op)
.ok_or(ErrorKind::InvalidBinop(
*op,
lhs_ref.resolve_deep().unwrap(),
rhs_ref.resolve_deep().unwrap(),
))?,
)
.unwrap())
} }
} }
ExprKind::FunctionCall(function_call) => { ExprKind::FunctionCall(function_call) => {
@ -366,7 +364,9 @@ impl Expression {
// many were provided) // many were provided)
let true_params_iter = fn_call.params.iter().chain(iter::repeat(&Vague(Unknown))); let true_params_iter = fn_call.params.iter().chain(iter::repeat(&Vague(Unknown)));
for (param_expr, param_t) in function_call.parameters.iter_mut().zip(true_params_iter) { for (param_expr, param_t) in
function_call.parameters.iter_mut().zip(true_params_iter)
{
let expr_res = param_expr.infer_types(state, type_refs); let expr_res = param_expr.infer_types(state, type_refs);
if let Some(mut param_ref) = state.ok(expr_res, param_expr.1) { if let Some(mut param_ref) = state.ok(expr_res, param_expr.1) {
param_ref.narrow(&mut type_refs.from_type(param_t).unwrap()); param_ref.narrow(&mut type_refs.from_type(param_t).unwrap());
@ -397,10 +397,12 @@ impl Expression {
// Narrow LHS to the same type as RHS and return it's return type // Narrow LHS to the same type as RHS and return it's return type
if let (Some(mut lhs_hints), Some(mut rhs_hints)) = (lhs_hints, rhs_hints) { if let (Some(mut lhs_hints), Some(mut rhs_hints)) = (lhs_hints, rhs_hints) {
lhs_hints.narrow(&mut rhs_hints).ok_or(ErrorKind::TypesIncompatible( lhs_hints
lhs_hints.resolve_deep().unwrap(), .narrow(&mut rhs_hints)
rhs_hints.resolve_deep().unwrap(), .ok_or(ErrorKind::TypesIncompatible(
)) lhs_hints.resolve_deep().unwrap(),
rhs_hints.resolve_deep().unwrap(),
))
} else { } else {
// Failed to retrieve types from either // Failed to retrieve types from either
Ok(type_refs.from_type(&Vague(Unknown)).unwrap()) Ok(type_refs.from_type(&Vague(Unknown)).unwrap())
@ -456,10 +458,15 @@ impl Expression {
} }
Ok(type_refs Ok(type_refs
.from_type(&Array(Box::new(first.as_type()), expressions.len() as u64)) .from_type(&Array(
Box::new(first.as_type()),
expressions.len() as u64,
))
.unwrap()) .unwrap())
} else { } else {
Ok(type_refs.from_type(&Array(Box::new(TypeKind::Void), 0)).unwrap()) Ok(type_refs
.from_type(&Array(Box::new(TypeKind::Void), 0))
.unwrap())
} }
} }
Err(errors) => { Err(errors) => {
@ -503,7 +510,10 @@ impl Expression {
let expected_struct_ty = state let expected_struct_ty = state
.scope .scope
.get_struct_type(&type_key) .get_struct_type(&type_key)
.ok_or(ErrorKind::NoSuchType(struct_name.clone(), state.module_id.unwrap()))? .ok_or(ErrorKind::NoSuchType(
struct_name.clone(),
state.module_id.unwrap(),
))?
.clone(); .clone();
for field in fields { for field in fields {
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) { if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
@ -513,12 +523,17 @@ impl Expression {
} }
} else { } else {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
Err(ErrorKind::NoSuchField(format!("{}.{}", struct_name, field.0))), Err(ErrorKind::NoSuchField(format!(
"{}.{}",
struct_name, field.0
))),
field.1 .1, field.1 .1,
); );
} }
} }
Ok(type_refs.from_type(&TypeKind::CustomType(type_key.clone())).unwrap()) Ok(type_refs
.from_type(&TypeKind::CustomType(type_key.clone()))
.unwrap())
} }
ExprKind::Borrow(var, mutable) => { ExprKind::Borrow(var, mutable) => {
// Find variable type // Find variable type

269
reid/src/mir/typerefs.rs Normal file
View File

@ -0,0 +1,269 @@
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
rc::Rc,
};
use crate::mir::VagueType;
use super::{
pass::{ScopeBinopDef, ScopeBinopKey, Storage},
typecheck::ErrorKind,
BinaryOperator, TypeKind,
};
#[derive(Clone)]
pub struct TypeRef<'scope>(
pub(super) TypeIdRef,
pub(super) &'scope ScopeTypeRefs<'scope>,
);
impl<'scope> TypeRef<'scope> {
/// Resolve current type in a weak manner, not resolving any Arrays or
/// further inner types
pub fn resolve_weak(&self) -> Option<TypeKind> {
Some(self.1.types.retrieve_type(*self.0.borrow())?)
}
/// Resolve type deeply, trying to resolve any inner types as well.
pub fn resolve_deep(&self) -> Option<TypeKind> {
let resolved = self.resolve_weak()?;
match resolved {
TypeKind::Array(elem_ty, len) => {
let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_weak()?;
Some(TypeKind::Array(Box::new(resolved_elem_ty), len))
}
_ => Some(resolved),
}
}
pub fn narrow(&mut self, other: &TypeRef) -> Option<TypeRef<'scope>> {
self.1.combine_vars(self, other)
}
pub fn as_type(&self) -> TypeKind {
TypeKind::Vague(super::VagueType::TypeRef(*self.0.borrow()))
}
}
impl<'scope> std::fmt::Debug for TypeRef<'scope> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Hint")
.field(&self.0)
.field(&self.resolve_deep().unwrap())
.finish()
}
}
type TypeIdRef = Rc<RefCell<usize>>;
#[derive(Debug, Default)]
pub struct TypeRefs {
/// Simple list of types that variables can refrence
pub(super) hints: RefCell<Vec<TypeKind>>,
/// Indirect ID-references, referring to hints-vec
pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
}
impl TypeRefs {
pub fn new(&self, ty: &TypeKind) -> TypeIdRef {
let idx = self.hints.borrow().len();
let typecell = Rc::new(RefCell::new(idx));
self.type_refs.borrow_mut().push(typecell.clone());
self.hints.borrow_mut().push(ty.clone());
typecell
}
pub fn find(&self, ty: &TypeKind) -> Option<TypeIdRef> {
if ty.known().is_err() {
// Only do this for non-vague types that can not be further narrowed
// down.
return None;
}
if let Some(idx) = self
.hints
.borrow_mut()
.iter()
.enumerate()
.find(|(_, t)| *t == ty)
.map(|(i, _)| i)
{
Some(Rc::new(RefCell::new(idx)))
} else {
None
}
}
pub(super) unsafe fn recurse_type_ref(&self, mut idx: usize) -> TypeIdRef {
let refs = self.type_refs.borrow();
let mut inner_idx = refs.get_unchecked(idx);
let mut seen = HashSet::new();
while (*inner_idx.borrow()) != idx && !seen.contains(&idx) {
seen.insert(idx);
idx = *inner_idx.borrow();
inner_idx = refs.get_unchecked(idx);
}
return refs.get_unchecked(idx).clone();
}
pub fn retrieve_type(&self, idx: usize) -> Option<TypeKind> {
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
self.hints
.borrow()
.get(inner_idx)
.cloned()
.map(|t| match t {
TypeKind::Vague(VagueType::TypeRef(id)) => self.retrieve_type(id),
_ => Some(t),
})
.flatten()
}
}
#[derive(Debug)]
pub struct ScopeTypeRefs<'outer> {
pub types: &'outer TypeRefs,
outer: Option<&'outer ScopeTypeRefs<'outer>>,
/// Mapping of what types variables point to
variables: RefCell<HashMap<String, (bool, TypeIdRef)>>,
}
impl<'outer> ScopeTypeRefs<'outer> {
pub fn from(types: &'outer TypeRefs) -> ScopeTypeRefs<'outer> {
ScopeTypeRefs {
types,
outer: Default::default(),
variables: Default::default(),
}
}
pub fn new_var(
&'outer self,
name: String,
mutable: bool,
initial_ty: &TypeKind,
) -> Result<TypeRef<'outer>, ErrorKind> {
if self.variables.borrow().contains_key(&name) {
return Err(ErrorKind::VariableAlreadyDefined(name));
}
let type_ref = self.from_type(&initial_ty).unwrap();
self.variables
.borrow_mut()
.insert(name, (mutable, type_ref.0.clone()));
Ok(type_ref)
}
pub fn from_type(&'outer self, ty: &TypeKind) -> Option<TypeRef<'outer>> {
let idx = match ty {
TypeKind::Vague(super::VagueType::TypeRef(idx)) => {
let inner_idx = unsafe { *self.types.recurse_type_ref(*idx).borrow() };
self.types.type_refs.borrow().get(inner_idx).cloned()?
}
TypeKind::Vague(_) => self.types.new(ty),
TypeKind::Array(elem_ty, length) => {
let elem_ty = self.from_type(elem_ty)?;
self.types
.new(&TypeKind::Array(Box::new(elem_ty.as_type()), *length))
}
TypeKind::Borrow(ty, mutable) => {
let inner_ty = self.from_type(ty)?;
self.types
.new(&&TypeKind::Borrow(Box::new(inner_ty.as_type()), *mutable))
}
_ => {
if let Some(ty_ref) = self.types.find(ty) {
ty_ref
} else {
self.types.new(ty)
}
}
};
Some(TypeRef(idx, self))
}
fn narrow_to_type(&'outer self, hint: &TypeRef, ty: &TypeKind) -> Option<TypeRef<'outer>> {
unsafe {
let mut hints = self.types.hints.borrow_mut();
let existing = hints.get_unchecked_mut(*hint.0.borrow());
*existing = existing.collapse_into(&ty).ok()?;
Some(TypeRef(hint.0.clone(), self))
}
}
fn combine_vars(&'outer self, hint1: &TypeRef, hint2: &TypeRef) -> Option<TypeRef<'outer>> {
unsafe {
let ty = self
.types
.hints
.borrow()
.get_unchecked(*hint2.0.borrow())
.clone();
self.narrow_to_type(&hint1, &ty)?;
for idx in self.types.type_refs.borrow_mut().iter_mut() {
if *idx == hint2.0 && idx != &hint1.0 {
*idx.borrow_mut() = *hint1.0.borrow();
}
}
Some(TypeRef(hint1.0.clone(), self))
}
}
pub fn inner(&'outer self) -> ScopeTypeRefs<'outer> {
ScopeTypeRefs {
types: self.types,
outer: Some(self),
variables: Default::default(),
}
}
pub fn find_var(&'outer self, name: &String) -> Option<(bool, TypeRef<'outer>)> {
self.variables
.borrow()
.get(name)
.map(|(mutable, idx)| (*mutable, TypeRef(idx.clone(), self)))
.or(self.outer.map(|o| o.find_var(name)).flatten())
}
pub fn binop(
&'outer self,
op: &BinaryOperator,
lhs: &mut TypeRef<'outer>,
rhs: &mut TypeRef<'outer>,
binops: &Storage<ScopeBinopKey, ScopeBinopDef>,
) -> Option<TypeRef<'outer>> {
if lhs.resolve_deep().unwrap().known().is_err()
&& rhs.resolve_deep().unwrap().known().is_err()
{
return self.from_type(&TypeKind::Vague(VagueType::Unknown));
}
let mut iter = binops.iter();
loop {
let Some((_, binop)) = iter.next() else {
break None;
};
if let Some(ret) = try_binop(lhs, rhs, binop) {
break Some(ret);
}
if binop.operator.is_commutative() {
if let Some(ret) = try_binop(rhs, lhs, binop) {
return Some(ret);
}
}
}
}
}
fn try_binop<'o>(
lhs: &mut TypeRef<'o>,
rhs: &mut TypeRef<'o>,
binop: &ScopeBinopDef,
) -> Option<TypeRef<'o>> {
let (lhs_ty, rhs_ty, ret_ty) =
TypeKind::binop_type(&lhs.resolve_deep()?, &rhs.resolve_deep()?, binop)?;
lhs.narrow(&lhs.1.from_type(&lhs_ty).unwrap()).unwrap();
rhs.narrow(&rhs.1.from_type(&rhs_ty).unwrap()).unwrap();
lhs.1.from_type(&ret_ty)
}

View File

@ -19,14 +19,3 @@ pub fn try_all<U, E>(list: Vec<Result<U, E>>) -> Result<Vec<U>, Vec<E>> {
Ok(successes) Ok(successes)
} }
} }
pub fn maybe<T, U>(lhs: Option<U>, rhs: Option<U>, fun: T) -> Option<U>
where
T: FnOnce(U, U) -> U,
{
if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
Some(fun(lhs, rhs))
} else {
None
}
}