Compare commits

...

14 Commits

27 changed files with 1972 additions and 1350 deletions

View File

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

View File

@ -47,13 +47,13 @@ Currently missing big features (TODOs) are:
- ~~Intrinsic functions~~ (DONE)
- ~~Ability to specify types in literals and variable definitions~~ (DONE)
- ~~Debug Information~~ (DONE)
- Fix struct initialization (wrong order and missing fields allowed now)
- Not-Unary
- ~~Fix struct initialization (wrong order and missing fields allowed now)~~
- ~~Not-Unary~~
- Importing types from other modules
- Importable binops?
- Associated functions (for e.g. sizeof)
Big features that I want later but are not necessary:
- Associated functions
- ~~User-defined binary operations~~ (DONE)
- ~~Asymmetric binary operations (e.g. string + u32)~~ (DONE)
- Error handling

6
examples/a.reid Normal file
View File

@ -0,0 +1,6 @@
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;
return value * other + 7 * -value;
}
}

View File

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

469
foo.reid Normal file
View File

@ -0,0 +1,469 @@
import std::concat_strings;
import std::print;
import std::from_str;
import std::free_string;
import std::add_num_to_str;
///////////////////
/// SDL externs ///
///////////////////
// Helper struct for stack allocated const sized strings, because structs are
// easier to create uninit than arrays.
struct SDL_Window {}
struct SDL_Renderer {}
struct SDL_Texture {}
struct SDL_Event { type: u32, reserved: [u8; 124] }
struct SDL_FRect { x: f32, y: f32, w: f32, h: f32 }
struct SDL_Rect { x: i32, y: i32, w: i32, h: i32 }
extern fn SDL_malloc(size: u64) -> *u8;
extern fn SDL_Init(flags: u32) -> bool;
extern fn SDL_Quit();
extern fn SDL_CreateWindowAndRenderer(title: *char, width: i32, height: i32, flags: i32,
window_out: &mut *SDL_Window, renderer_out: &mut *SDL_Renderer) -> bool;
extern fn SDL_Delay(ms: u32);
extern fn SDL_SetRenderDrawColor(renderer: *SDL_Renderer, r: u8, g: u8, b: u8, a: u8);
extern fn SDL_RenderClear(renderer: *SDL_Renderer);
extern fn SDL_RenderPresent(renderer: *SDL_Renderer);
extern fn SDL_HasEvent(event_type: u32) -> bool;
extern fn SDL_PollEvent(event: &mut SDL_Event) -> bool;
extern fn SDL_PumpEvents();
extern fn SDL_FlushEvents(min_type: u32, max_type: u32);
extern fn SDL_GetTicks() -> u64;
extern fn SDL_SetWindowTitle(window: *SDL_Window, title: *char) -> bool;
extern fn SDL_CreateTexture(renderer: *SDL_Renderer,
pixel_format: u32, texture_access: u32, width: u32, height: u32) -> *SDL_Texture;
extern fn SDL_RenderTexture(renderer: *SDL_Renderer,
texture: *SDL_Texture, srcfrect: &SDL_FRect, dstfrect: &SDL_FRect) -> bool;
extern fn SDL_UpdateTexture(texture: *SDL_Texture, rect: &SDL_Rect, pixels: *u8, pitch: u32) -> bool;
extern fn SDL_GetError() -> *char;
extern fn SDL_GetWindowSize(window: *SDL_Window, w: &mut i32, h: &mut i32) -> bool;
extern fn SDL_rand(max_exclusive: u32) -> u32;
extern fn SDL_SetTextureScaleMode(texture: *SDL_Texture, scale_mode: i32) -> bool;
extern fn SDL_sqrtf(value: f32) -> f32;
extern fn SDL_randf() -> f32;
extern fn SDL_powf(value: f32, power: f32) -> f32;
// SDL error reporting helper
fn print_sdl_error(context: *char) {
let mut message = from_str(context);
let delim = from_str(": ");
concat_strings(&mut message, delim);
free_string(&delim);
let error_msg = from_str(SDL_GetError());
concat_strings(&mut message, error_msg);
free_string(&error_msg);
print(message);
free_string(&message);
}
/////////////////////////////////
/// Main setup and frame loop ///
/////////////////////////////////
struct GameState {
renderer: *SDL_Renderer,
window: *SDL_Window,
render_texture: *SDL_Texture,
frame_counter: u32,
last_fps_reset: u64,
pixels: *u8,
pixels_w: u32,
pixels_h: u32,
pixels_bpp: u32,
}
fn main() -> i32 {
let SDL_INIT_VIDEO = 32;
let SDL_WINDOW_RESIZABLE = 32;
let SDL_PIXELFORMAT_RGBA8888 = 373694468;
let SDL_PIXELFORMAT_ABGR8888 = 376840196;
let SDL_PIXELFORMAT_RGB24 = 386930691;
let SDL_PIXELFORMAT_BGR24 = 390076419;
let SDL_PIXELFORMAT_RGB96_FLOAT = 454057996;
let SDL_PIXELFORMAT_BGR96_FLOAT = 457203724;
let SDL_TEXTUREACCESS_STREAMING = 1;
let SDL_SCALEMODE_NEAREST = 0;
let SDL_SCALEMODE_LINEAR = 1;
let SDL_SCALEMODE_PIXELART = 2;
let init_success = SDL_Init(SDL_INIT_VIDEO);
if init_success == false {
print_sdl_error("SDL init failed");
return 1;
}
let mut window = SDL_malloc(1) as *SDL_Window;
let mut renderer = SDL_malloc(1) as *SDL_Renderer;
let gfx_init_success = SDL_CreateWindowAndRenderer(
"graphical reid program", 640, 480, SDL_WINDOW_RESIZABLE,
&mut window, &mut renderer
);
if gfx_init_success == false {
print_sdl_error("SDL renderer and window creation failed");
return 1;
}
let width = 320;
let height = 240;
let bpp = 4;
let render_texture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height);
SDL_SetTextureScaleMode(render_texture, SDL_SCALEMODE_NEAREST);
let pixels_len = (width * height * bpp) as u64;
let pixels = SDL_malloc(pixels_len);
let mut game_state = GameState {
renderer: renderer,
window: window,
render_texture: render_texture,
frame_counter: 0,
last_fps_reset: 0,
pixels: pixels,
pixels_w: width,
pixels_h: height,
pixels_bpp: bpp,
};
while frame_loop(&mut game_state) {}
SDL_Quit();
return 0;
}
fn frame_loop(game_state: &mut GameState) -> bool {
let mut event = SDL_Event {};
while (SDL_PollEvent(&mut event)) {
if event.type == 256 { // SDL_EVENT_QUIT
return false;
}
}
let mut screen_width = 0;
let mut screen_height = 0;
SDL_GetWindowSize(*game_state.window, &mut screen_width, &mut screen_height);
let renderer = *game_state.renderer;
SDL_SetRenderDrawColor(renderer, 0, 50, 90, 255);
SDL_RenderClear(renderer);
let w = *game_state.pixels_w;
let h = *game_state.pixels_h;
let bpp = *game_state.pixels_bpp;
for y in 0..h {
for x in 0..w {
render_pixel(x, y, game_state);
}
}
let texture_area = SDL_Rect { x: 0, y: 0, w: w as i32, h: h as i32 };
if SDL_UpdateTexture(*game_state.render_texture, &texture_area, *game_state.pixels as *u8, bpp * w) == false {
print_sdl_error("UpdateTexture error");
}
let src = SDL_FRect { x: 0.0, y: 0.0, w: w as f32, h: h as f32 };
let aspect_ratio = src.w / src.h;
let scaled_width = screen_height as f32 * aspect_ratio;
let dst = SDL_FRect { x: (screen_width as f32 - scaled_width) / 2.0, y: 0.0, w: scaled_width, h: screen_height as f32 };
if SDL_RenderTexture(renderer, *game_state.render_texture, &src, &dst) == false {
print_sdl_error("RenderTexture error");
}
SDL_RenderPresent(renderer);
SDL_Delay(1);
*game_state.frame_counter = *game_state.frame_counter + 1;
let t = SDL_GetTicks();
if (t - *game_state.last_fps_reset) >= 1000 {
let mut title = from_str("graphical reid program ");
add_num_to_str(&mut title, *game_state.frame_counter as u64);
let fps_unit = from_str(" fps");
concat_strings(&mut title, fps_unit);
free_string(&fps_unit);
SDL_SetWindowTitle(*game_state.window, title.inner);
free_string(&title);
*game_state.frame_counter = 0;
*game_state.last_fps_reset = t;
}
return true;
}
fn render_pixel(x: u32, y: u32, game_state: &mut GameState) {
let w = *game_state.pixels_w;
let h = *game_state.pixels_h;
let bpp = *game_state.pixels_bpp;
let samples = 1;
let old_sample_weight = 0.75;
let new_sample_weight = 0.25 / samples as f32;
let mut rgb = vec_mul_scalar(old_sample_weight, [
srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 0]),
srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 1]),
srgb_to_linear(*game_state.pixels[(x + y * w) * bpp + 2])
]);
for sample in 0..samples {
rgb = vec_add(rgb, vec_mul_scalar(new_sample_weight, shade(x, y, *game_state.frame_counter, w, h)));
}
*game_state.pixels[(x + y * w) * bpp + 0] = linear_to_srgb(rgb[0]);
*game_state.pixels[(x + y * w) * bpp + 1] = linear_to_srgb(rgb[1]);
*game_state.pixels[(x + y * w) * bpp + 2] = linear_to_srgb(rgb[2]);
*game_state.pixels[(x + y * w) * bpp + 3] = 255;
}
/////////////////
/// Rendering ///
/////////////////
struct Ray {
origin: [f32; 3],
direction: [f32; 3],
}
struct Material {
// 0 = lambertian diffuse
// 1 = mirror
type: u32,
// Generally the "color" of the surface (linear factors of how much of each
// color channel this surface does not absorb), but the idea is that the
// type governs what this means.
linear_color: [f32; 3],
}
struct Hit {
hit: bool,
front_face: bool,
distance: f32,
normal: [f32; 3],
position: [f32; 3],
material: Material,
}
struct Sphere {
center: [f32; 3],
radius: f32,
material: Material,
}
fn shade(x: u32, y: u32, t: u32, w: u32, h: u32) -> [f32; 3] {
let jitter_x = SDL_randf() - 0.5;
let jitter_y = SDL_randf() - 0.5;
let pixel_scale = 1.0 / h as f32;
let pixel_pos = [
(x as f32 + jitter_x) * pixel_scale,
1.0 - (y as f32 + jitter_y) * pixel_scale,
0.0 - 1.0
];
let camera_pos = [w as f32 * 0.5f32 * pixel_scale, h as f32 * 0.5f32 * pixel_scale, 0.0f32];
let dir = vec_normalize(vec_sub(pixel_pos, camera_pos));
let ray = Ray { origin: camera_pos, direction: dir };
let beige_lambertian = Material { type: 0, linear_color: [0.3, 0.2, 0.1] };
let green_lambertian = Material { type: 0, linear_color: [0.1, 0.5, 0.06] };
let greenish_mirror = Material { type: 1, linear_color: [0.9, 1.0, 0.95] };
let spheres = [
// Ground
Sphere { center: vec_sub(camera_pos, [0.0, 100001.0, 0.0]), radius: 100000.0, material: beige_lambertian },
// Centered unit sphere
Sphere { center: vec_add(camera_pos, [0.0, 0.0, 0.0 - 5.0]), radius: 1.0, material: green_lambertian },
// The unit sphere on the right
Sphere { center: vec_add(camera_pos, [2.0, 0.0, 0.0 - 6.0]), radius: 1.0, material: greenish_mirror }
];
return shade_world(ray, &spheres, 3);
}
fn shade_world(ray: Ray, spheres: &[Sphere; 3], bounces_left: u8) -> [f32; 3] {
if bounces_left == 0 {
return [0.0, 0.0, 0.0];
}
let ray_distance = 100.0;
let mut closest_hit = Hit { hit: false, front_face: false, distance: ray_distance };
for i in 0..3 {
let sphere_hit = ray_sphere_closest_hit(ray, *spheres[i], [0.001, closest_hit.distance]);
if sphere_hit.hit {
closest_hit = sphere_hit;
}
}
if closest_hit.hit {
//return vec_mul_scalar(0.5, vec_add(closest_hit.normal, [1.0, 1.0, 1.0])); // normal
//return vec_mul_scalar(closest_hit.distance / 10.0, [1.0, 1.0, 1.0]); // depth
if closest_hit.material.type == 0 {
let bounce_dir = vec_normalize(vec_add(closest_hit.normal, random_unit_vec()));
let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir };
return vec_mul_componentwise(
closest_hit.material.linear_color,
shade_world(bounce_ray, spheres, bounces_left - 1)
);
} else if closest_hit.material.type == 1 {
let bounce_dir = vec_reflect(ray.direction, closest_hit.normal);
let bounce_ray = Ray { origin: closest_hit.position, direction: bounce_dir };
return vec_mul_componentwise(
closest_hit.material.linear_color,
shade_world(bounce_ray, spheres, bounces_left - 1)
);
} else {
return [1.0, 0.0, 1.0];
}
}
return shade_sky(ray);
}
fn shade_sky(ray: Ray) -> [f32; 3] {
let a = 0.5 * (ray.direction[1] + 1.0);
return vec_add(
vec_mul_scalar(1.0 - a, [1.0, 1.0, 1.0]),
vec_mul_scalar(a, [0.5, 0.7, 1.0])
);
}
// Returns the distance from the ray origin to the sphere, or -1.0 if the ray doesn't hit.
fn ray_sphere_closest_hit(ray: Ray, sphere: Sphere, interval: [f32; 2]) -> Hit {
let to_sphere = vec_sub(sphere.center, ray.origin);
let h = vec_dot(ray.direction, to_sphere);
let c = vec_length_squared(to_sphere) - sphere.radius * sphere.radius;
let discriminant = h * h - c;
if discriminant < 0.0 {
return Hit { hit: false };
}
let discriminant_sqrt = SDL_sqrtf(discriminant);
let mut distance = h - discriminant_sqrt;
if interval_surrounds(interval, distance) == false {
distance = h - discriminant_sqrt;
if interval_surrounds(interval, distance) == false {
return Hit { hit: false };
}
}
let hit_position = vec_add(ray.origin, vec_mul_scalar(distance, ray.direction));
let mut front_face = true;
let mut normal = vec_normalize(vec_sub(hit_position, sphere.center));
if vec_dot(normal, ray.direction) > 0.0 {
normal = vec_mul_scalar(0.0 - 1.0, normal);
front_face = false;
}
return Hit {
hit: true,
front_face: front_face,
distance: distance,
normal: normal,
position: hit_position,
material: sphere.material,
};
}
//////////////////
/// Other math ///
//////////////////
fn clamp(min: f32, max: f32, value: f32) -> f32 {
if value > max {
return max;
}
if value < min {
return min;
}
return value;
}
fn abs(f: f32) -> f32 {
if f < 0.0 {
return f * (0.0 - 1.0);
}
return f;
}
fn vec_add(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] {
return [lhs[0] + rhs[0], lhs[1] + rhs[1], lhs[2] + rhs[2]];
}
fn vec_sub(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] {
return [lhs[0] - rhs[0], lhs[1] - rhs[1], lhs[2] - rhs[2]];
}
fn vec_dot(lhs: [f32; 3], rhs: [f32; 3]) -> f32 {
return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2];
}
fn vec_mul_componentwise(lhs: [f32; 3], rhs: [f32; 3]) -> [f32; 3] {
return [lhs[0] * rhs[0], lhs[1] * rhs[1], lhs[2] * rhs[2]];
}
fn vec_mul_scalar(lhs: f32, rhs: [f32; 3]) -> [f32; 3] {
return [lhs * rhs[0], lhs * rhs[1], lhs * rhs[2]];
}
fn vec_normalize(v: [f32; 3]) -> [f32; 3] {
let len_reciprocal = 1.0f32 / SDL_sqrtf(vec_length_squared(v));
return vec_mul_scalar(len_reciprocal, v);
}
fn vec_length_squared(v: [f32; 3]) -> f32 {
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
}
fn vec_abs(v: [f32; 3]) -> [f32; 3] {
return [abs(v[0]), abs(v[1]), abs(v[2])];
}
fn vec_reflect(direction: [f32; 3], normal: [f32; 3]) -> [f32; 3] {
return vec_sub(direction, vec_mul_scalar(2.0f32 * vec_dot(direction, normal), normal));
}
fn interval_surrounds(interval: [f32; 2], value: f32) -> bool {
return (interval[0] < value) && (value < interval[1]);
}
fn random_unit_vec() -> [f32; 3] {
let mut point = [
SDL_randf() * 2.0f32 - 1.0f32,
SDL_randf() * 2.0f32 - 1.0f32,
SDL_randf() * 2.0f32 - 1.0f32
];
let mut lensq = vec_length_squared(point);
while lensq > 1.0 {
point = [
SDL_randf() * 2.0f32 - 1.0f32,
SDL_randf() * 2.0f32 - 1.0f32,
SDL_randf() * 2.0f32 - 1.0f32
];
lensq = vec_length_squared(point);
}
let len_reciprocal = 1.0f32 / SDL_sqrtf(lensq);
return vec_mul_scalar(len_reciprocal, point);
}
fn random_unit_vec_on_hemi(normal: [f32; 3]) -> [f32; 3] {
let rand_vec = random_unit_vec();
if vec_dot(rand_vec, normal) < 0.0f32 {
return vec_mul_scalar(0.0f32 - 1.0f32, rand_vec);
}
return rand_vec;
}
fn linear_to_srgb(linear: f32) -> u8 {
let mut floating_srgb = 0.0;
if linear <= 0.0031308f32 {
floating_srgb = 12.92f32 * linear;
} else {
floating_srgb = SDL_powf(linear as f32, 1.0 / 2.4) * 1.055f32 - 0.055f32;
}
let clamped = clamp(0.0, 1.0, floating_srgb);
return (clamped * 255.999) as u8;
}
fn srgb_to_linear(srgb: u8) -> f32 {
let floating_srgb = srgb as f32 / 255.0;
if floating_srgb <= 0.04045f32 {
return floating_srgb / 12.92f32;
}
return SDL_powf((floating_srgb as f32 + 0.055) / 1.055, 2.4);
}

View File

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

View File

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

View File

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

View File

@ -87,6 +87,7 @@ impl Parse for UnaryOperator {
match token {
Token::Plus => Ok(UnaryOperator::Plus),
Token::Minus => Ok(UnaryOperator::Minus),
Token::Exclamation => Ok(UnaryOperator::Not),
_ => Err(stream.expected_err("unary operator")?),
}
} else {
@ -174,20 +175,11 @@ impl Parse for PrimaryExpression {
use ExpressionKind as Kind;
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() {
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() {
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()) {
stream.next(); // Consume Et
stream.next(); // Consume mut
@ -195,15 +187,11 @@ impl Parse for PrimaryExpression {
return Err(stream.expected_err("identifier")?);
};
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 identifier
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 identifier
Expression(Kind::Deref(name), stream.get_range().unwrap())
@ -225,49 +213,35 @@ impl Parse for PrimaryExpression {
}
Token::BinaryValue(v) => {
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) {
expr
} else {
Expression(
Kind::Literal(Literal::Integer(value)),
stream.get_range().unwrap(),
)
Expression(Kind::Literal(Literal::Integer(value)), stream.get_range().unwrap())
}
}
Token::OctalValue(v) => {
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) {
expr
} else {
Expression(
Kind::Literal(Literal::Integer(value)),
stream.get_range().unwrap(),
)
Expression(Kind::Literal(Literal::Integer(value)), stream.get_range().unwrap())
}
}
Token::HexadecimalValue(v) => {
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) {
expr
} else {
Expression(
Kind::Literal(Literal::Integer(value)),
stream.get_range().unwrap(),
)
Expression(Kind::Literal(Literal::Integer(value)), stream.get_range().unwrap())
}
}
Token::DecimalValue(v) => {
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 fractional
@ -278,30 +252,20 @@ impl Parse for PrimaryExpression {
if let Ok(expr) = specific_float_lit(value, &mut stream) {
expr
} else {
Expression(
Kind::Literal(Literal::Decimal(value)),
stream.get_range().unwrap(),
)
Expression(Kind::Literal(Literal::Decimal(value)), stream.get_range().unwrap())
}
} 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) {
expr
} else {
Expression(
Kind::Literal(Literal::Integer(value)),
stream.get_range().unwrap(),
)
Expression(Kind::Literal(Literal::Integer(value)), stream.get_range().unwrap())
}
}
}
Token::StringLit(v) => {
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) => {
stream.next(); // Consume
@ -319,17 +283,11 @@ impl Parse for PrimaryExpression {
}
Token::True => {
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 => {
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 => {
stream.next(); // Consume
@ -343,16 +301,14 @@ impl Parse for PrimaryExpression {
if let Some(Token::Semi) = stream.peek() {
stream.next(); // Consume colon
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)?;
Expression(
Kind::ArrayShort(
Box::new(exp),
u64::from_str_radix(&val, 10).expect(
"Unable to parse array length to 64-bit decimal value",
),
u64::from_str_radix(&val, 10)
.expect("Unable to parse array length to 64-bit decimal value"),
),
stream.get_range().unwrap(),
)
@ -514,11 +470,7 @@ impl Parse for FunctionCallExpression {
stream.expect(Token::ParenClose)?;
Ok(FunctionCallExpression(
name,
args,
stream.get_range().unwrap(),
))
Ok(FunctionCallExpression(name, args, stream.get_range().unwrap()))
} else {
Err(stream.expected_err("identifier")?)
}
@ -535,12 +487,7 @@ impl Parse for IfExpression {
} else {
None
};
Ok(IfExpression(
cond,
then_b,
else_b,
stream.get_range().unwrap(),
))
Ok(IfExpression(cond, then_b, else_b, stream.get_range().unwrap()))
}
}
@ -700,11 +647,7 @@ impl Parse for Block {
statements.push(statement);
}
stream.expect(Token::BraceClose)?;
Ok(Block(
statements,
return_stmt,
stream.get_range_prev().unwrap(),
))
Ok(Block(statements, return_stmt, stream.get_range_prev().unwrap()))
}
}
@ -809,9 +752,7 @@ impl Parse for BlockLevelStatement {
use BlockLevelStatement as Stmt;
Ok(match stream.peek() {
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) => {
stream.next();
let exp = stream.parse().ok();
@ -924,9 +865,7 @@ impl Parse for TopLevelStatement {
stream.expect(Token::Semi)?;
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) => {
let StructDefinition(name, fields, range) = stream.parse::<StructDefinition>()?;
Stmt::TypeDefinition(TypeDefinition {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,6 @@
use super::{pass::ScopeBinopDef, typecheck::ErrorKind, typerefs::TypeRefs, VagueType as Vague, *};
use crate::util::maybe;
use super::{pass::ScopeBinopDef, typecheck::typerefs::TypeRefs, *};
#[derive(Debug, Clone)]
pub enum ReturnTypeOther {
@ -12,87 +14,18 @@ pub enum ReturnTypeOther {
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 {
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
/// values of this type
pub fn simple_binop_type(&self, op: &BinaryOperator) -> Option<TypeKind> {
@ -110,20 +43,6 @@ 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
/// 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> {
@ -141,22 +60,6 @@ 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 {
match self {
TypeKind::Bool => false,
@ -297,9 +200,9 @@ impl TypeKind {
(lhs1, rhs1): (&TypeKind, &TypeKind),
(lhs2, rhs2): (&TypeKind, &TypeKind),
) -> Option<(TypeKind, TypeKind)> {
if let (Ok(lhs), Ok(rhs)) = (lhs1.collapse_into(&lhs2), rhs1.collapse_into(&rhs2)) {
if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&lhs2), rhs1.narrow_into(&rhs2)) {
Some((lhs, rhs))
} else if let (Ok(lhs), Ok(rhs)) = (lhs1.collapse_into(&rhs2), rhs1.collapse_into(&lhs2)) {
} else if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&rhs2), rhs1.narrow_into(&lhs2)) {
Some((rhs, lhs))
} else {
None
@ -365,11 +268,6 @@ impl StructType {
}
}
enum BlockReturn<'b> {
Early(&'b Statement),
Normal(ReturnKind, &'b Option<Box<Expression>>),
}
impl Block {
fn return_expr(&self) -> Result<BlockReturn, ReturnTypeOther> {
let mut early_return = None;
@ -461,10 +359,7 @@ impl Statement {
expr.return_type(refs, mod_id)?,
Err(ReturnTypeOther::Let(var.2 + expr.1)),
),
Set(lhs, rhs) => if_hard(
rhs.return_type(refs, mod_id)?,
Err(ReturnTypeOther::Set(lhs.1 + rhs.1)),
),
Set(lhs, rhs) => if_hard(rhs.return_type(refs, mod_id)?, Err(ReturnTypeOther::Set(lhs.1 + rhs.1))),
Import(_) => todo!(),
Expression(expression) => expression.return_type(refs, mod_id),
While(_) => Err(ReturnTypeOther::Loop),
@ -492,11 +387,14 @@ impl Expression {
match &self.0 {
Literal(lit) => Ok((ReturnKind::Soft, lit.as_type())),
Variable(var) => var.return_type(),
BinOp(_, then_e, else_e) => {
BinOp(_, then_e, else_e, return_ty) => {
let then_r = then_e.return_type(refs, mod_id)?;
let else_r = else_e.return_type(refs, mod_id)?;
Ok(pick_return(then_r, else_r))
Ok(match (then_r.0, else_r.0) {
(ReturnKind::Hard, ReturnKind::Hard) => (ReturnKind::Hard, return_ty.clone()),
_ => (ReturnKind::Soft, return_ty.clone()),
})
}
Block(block) => block.return_type(refs, mod_id),
FunctionCall(fcall) => fcall.return_type(),
@ -559,22 +457,14 @@ impl Expression {
ExprKind::Array(_) => None,
ExprKind::Struct(_, _) => None,
ExprKind::Literal(_) => None,
ExprKind::BinOp(_, _, _) => None,
ExprKind::BinOp(_, _, _, _) => None,
ExprKind::FunctionCall(_) => None,
ExprKind::If(_) => None,
ExprKind::CastTo(expression, _) => expression.backing_var(),
}
}
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> {
pub fn num_value(&self) -> Result<Option<i128>, NumValueError> {
Ok(match &self.0 {
ExprKind::Variable(_) => None,
ExprKind::Indexed(..) => None,
@ -582,7 +472,7 @@ impl Expression {
ExprKind::Array(_) => None,
ExprKind::Struct(..) => None,
ExprKind::Literal(literal) => literal.num_value(),
ExprKind::BinOp(op, lhs, rhs) => match op {
ExprKind::BinOp(op, lhs, rhs, _) => match op {
BinaryOperator::Add => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a + b),
BinaryOperator::Minus => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a - b),
BinaryOperator::Mult => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a * b),
@ -591,14 +481,14 @@ impl Expression {
BinaryOperator::Div => {
let rhs_value = rhs.num_value()?;
if rhs_value == Some(0) {
Err(ErrorKind::DivideZero)?
Err(NumValueError::DivideZero)?
}
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b)
}
BinaryOperator::Mod => {
let rhs_value = rhs.num_value()?;
if rhs_value == Some(0) {
Err(ErrorKind::DivideZero)?
Err(NumValueError::DivideZero)?
}
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a % b)
}
@ -613,16 +503,6 @@ 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 {
pub fn return_type(
&self,
@ -678,56 +558,6 @@ 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 {
pub fn num_value(&self) -> Option<i128> {
match self {
@ -774,9 +604,7 @@ pub enum EqualsIssue {
impl FunctionDefinition {
pub fn equals_as_imported(&self, other: &FunctionDefinition) -> Result<(), EqualsIssue> {
match &self.kind {
FunctionDefinitionKind::Local(_, metadata) => {
Err(EqualsIssue::ExistsLocally(*metadata))
}
FunctionDefinitionKind::Local(_, metadata) => Err(EqualsIssue::ExistsLocally(*metadata)),
FunctionDefinitionKind::Extern(imported) => {
if *imported {
Err(EqualsIssue::ConflictWithImport(self.name.clone()))
@ -788,10 +616,7 @@ impl FunctionDefinition {
{
Ok(())
} else {
Err(EqualsIssue::AlreadyExtern(
self.name.clone(),
self.signature(),
))
Err(EqualsIssue::AlreadyExtern(self.name.clone(), self.signature()))
}
}
}

View File

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

View File

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

View File

@ -0,0 +1,318 @@
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

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

View File

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

View File

@ -0,0 +1,404 @@
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

@ -1,269 +0,0 @@
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,3 +19,14 @@ pub fn try_all<U, E>(list: Vec<Result<U, E>>) -> Result<Vec<U>, Vec<E>> {
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
}
}