Compare commits

..

No commits in common. "main" and "lexical-scopes" have entirely different histories.

90 changed files with 4805 additions and 7883 deletions

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "reid-llvm-lib"]
path = reid-llvm-lib
url = gitea@git.teascade.net:teascade/reid-llvm-lib.git

1267
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
[workspace] [workspace]
members = [ members = [
"reid", "reid",
"reid-llvm-lib", "reid-llvm-lib"
"reid-lsp"
] ]

View File

@ -12,9 +12,6 @@ by simplicity.
Specifications and a bunch of [documentation for the language can be found Specifications and a bunch of [documentation for the language can be found
here](./documentation/). here](./documentation/).
An example of a real whole program (a CPU pathtracer) can be found [in
examples/cpu_raytracer.reid](./examples/cpu_raytracer.reid), go have a look!
Reid is currently able to (non-exhaustively): Reid is currently able to (non-exhaustively):
- Do basic algebra binary and unary-operations (e.g. Add, Sub, Div, Mult, And, - Do basic algebra binary and unary-operations (e.g. Add, Sub, Div, Mult, And,
Not) Not)
@ -71,22 +68,17 @@ Currently missing big features (TODOs) are:
Big features that I want later but are not necessary: Big features that I want later but are not necessary:
- ~~User-defined binary operations~~ (DONE) - ~~User-defined binary operations~~ (DONE)
- ~~Asymmetric binary operations (e.g. string + u32)~~ (DONE) - ~~Asymmetric binary operations (e.g. string + u32)~~ (DONE)
- ~~Error handling~~ (Not Doing It) - Error handling
- ~~Lexing & parsing of whitespace and comments as well~~ (DONE) - Lexing & parsing of whitespace and comments as well
- ~~LSP implementation~~ (DONE) - LSP implementation
- ~~Syntax Highlighting~~ (DONE)
- ~~Semantic Highlighting~~ (DONE)
- ~~Go-To-Definition~~ (DONE)
- ~~Find-All-References~~ (DONE)
- ~~Refactoring~~ (DONE)
Smaller features: Smaller features:
- ~~Hex-numbers~~ (DONE) - ~~Hex-numbers~~
- ~~Bitwise operations~~ (DONE) - ~~Bitwise operations~~
- ~~Easier way to initialize arrays with a single value~~ (DONE) - ~~Easier way to initialize arrays with a single value~~
- ~~Void-returns (`return;` for void-returning functions)~~ (DONE) - ~~Void-returns (`return;` for void-returning functions)~~
- ~~Only include standard library at all if it is imported~~ (DONE) - ~~Only include standard library at all if it is imported~~
- ~~Lexical scopes for Debug Information~~ (DONE) - Lexical scopes for Debug Information
### Why "Reid" ### Why "Reid"
@ -162,6 +154,10 @@ cmake llvm -B build -DCMAKE_BUILD_TYPE=MinSizeRel -DLLVM_ENABLE_ASSERTIONS=ON -D
ninja -j23 ninja -j23
``` ```
*Also Note:* Building LLVM with `Ninja` was not successful for me, but this
method was. Ninja may be successful with you, to try it, add `-G Ninja` to the
`cmake`-command, and instead of `make` run `ninja install`.
### Building this crate itself ### Building this crate itself
Assuming `llvm-project` from the previous step was at Assuming `llvm-project` from the previous step was at
@ -171,5 +167,6 @@ Assuming `llvm-project` from the previous step was at
LLVM_SYS_201_PREFIX=/path/llvm-project/build cargo build LLVM_SYS_201_PREFIX=/path/llvm-project/build cargo build
``` ```
Alternatively assuming you have LLVM 20.1 or newer installed you may use omit ## In conclusion
the environment variable entirely and use dynamic linking instead Good luck! It took me a good 10 hours to figure this out for myself, I sure hope
these instructions help both myself and someone else in the future!

View File

@ -27,9 +27,7 @@ in-depth, but when you're feeling up to it, you can read about them
## Syntax and general information ## Syntax and general information
Syntax for Reid is very much inspired by rust, and examples of the language can Syntax for Reid is very much inspired by rust, and examples of the language can
be found in the [examples](../examples/)-folder. A larger example of a whole be found in the [examples](../examples/)-folder.
program written in Reid (a CPU Pathtracer) can be found [in
examples/cpu_raytracer.reid](../examples/cpu_raytracer.reid).
In Reid **modules** (or files) on the top-level are comprised of imports, type In Reid **modules** (or files) on the top-level are comprised of imports, type
definitions, binop-definitions, functions and type-associated function blocks. definitions, binop-definitions, functions and type-associated function blocks.
@ -83,11 +81,7 @@ Common token used throughout this document to express parts of grammar include:
"i8" | "i16" | "i32" | "i64" | "i128" | "i8" | "i16" | "i32" | "i64" | "i128" |
"f16" | "f32" | "f32b" | "f64" | "f80" | "f128" | "f128ppc" "f16" | "f32" | "f32b" | "f64" | "f80" | "f128" | "f128ppc"
<binop> :: "+" | "-" | "*" <binop> :: "+" | "-" | "*" | "/" | "%" | "&&" | <cmp>
| "/" | "%" | "&&" | "||"
| "&" | "|" | "^" | ">>"
| "<<" | <cmp>
<cmp> :: "<" | "<=" | "==" | "!=" | ">=" | >" <cmp> :: "<" | "<=" | "==" | "!=" | ">=" | >"
<unary> :: "+" | "-" | "!" <unary> :: "+" | "-" | "!"
``` ```
@ -261,9 +255,6 @@ calls, literals, or if-expressions. Types of supported expressions include:
*associated type* with given parameters. *associated type* with given parameters.
- **Accessing function calls**, a shorthand to call associated function calls - **Accessing function calls**, a shorthand to call associated function calls
which have `&self` or `&mut self` as their first parameter. which have `&self` or `&mut self` as their first parameter.
- **Macro invocations** for invoking **macros** which are evaluated at
compile-time rather than runtime. Currently it is not possible to define
your own macros, but there are some pre-defined in the intrinsics.
- **Block-expressions**, which can return a value to the higher-level expression - **Block-expressions**, which can return a value to the higher-level expression
if they have a statement with a soft-return. Otherwise they return void. if they have a statement with a soft-return. Otherwise they return void.
- **If-expressions**, which can execute one of two expressions depending on the - **If-expressions**, which can execute one of two expressions depending on the
@ -281,7 +272,7 @@ In formal grammar:
<indexing> | <accessing> | <indexing> | <accessing> |
<binary-exp> | <unary-exp> | <binary-exp> | <unary-exp> |
<function-call> | <accessing-function-call> | <assoc-function-call> <function-call> | <accessing-function-call> | <assoc-function-call>
<macro-invocation> | <block> | <if-expr> | <cast> | <block> | <if-expr> | <cast> |
( "(" <expression> ")" ) ( "(" <expression> ")" )
<variable> :: <ident> <variable> :: <ident>
@ -297,7 +288,6 @@ In formal grammar:
<function-call> :: <expression> "(" [ <expression> ( "," <expression> )* ] ")" <function-call> :: <expression> "(" [ <expression> ( "," <expression> )* ] ")"
<accessing-function-call> :: <accessing> "(" [ <expression> ( "," <expression> )* ] ")" <accessing-function-call> :: <accessing> "(" [ <expression> ( "," <expression> )* ] ")"
<assoc-function-call> :: <type> "::" <function-call> <assoc-function-call> :: <type> "::" <function-call>
<macro-invocation> :: <expression> "!(" [ <expression> ( "," <expression> )* ] ")"
<if-expr> :: "if" <expression> <expression> [ "else" <expression> ] <if-expr> :: "if" <expression> <expression> [ "else" <expression> ]
<cast> :: <expression> "as" <type> <cast> :: <expression> "as" <type>
``` ```
@ -316,7 +306,6 @@ test.first // Accessing
func(value, 14) // Function call func(value, 14) // Function call
Test::get_field(&test); // Associated function call Test::get_field(&test); // Associated function call
test.get_field(); // Same, but using a the dot-form shorthand test.get_field(); // Same, but using a the dot-form shorthand
include_bytes!("./test"); // Macro invocation
if varname {} else {} // If-expression if varname {} else {} // If-expression
value as u32 // cast value as u32 // cast
(value + 2) // Binop within parenthesis (value + 2) // Binop within parenthesis

View File

@ -7,22 +7,14 @@ pre-existing binary-operators, but also some regular functions and associated
functions (that every type has by-default). This document lists them all (except functions (that every type has by-default). This document lists them all (except
for the binary operators, because there are hundreds of those). for the binary operators, because there are hundreds of those).
### Macro Intrinsics
#### `include_bytes!(path: *char) -> &[u8; _]`
Attempts to load file from `path` (relative to module) into memory and includes
it into the compiled binary directly. Returns a borrow to an array containing
bytes from the file. Array length varies depending on the file contents.
### Associated Intrinsics ### Associated Intrinsics
#### `<T>::sizeof() -> u64` #### `<T>::sizeof() -> u64`
Simply returns the size of type `T` in bytes. Simply returns the size of type `T` in bits.
```rust ```rust
i32::sizeof(); // Returns 4 i32::sizeof(); // Returns 32
``` ```
#### `<T>::null() -> *T` #### `<T>::null() -> *T`
@ -33,155 +25,12 @@ Returns a null-pointer of type `T`.
i32::null(); // Returns *i32 (null-ptr) i32::null(); // Returns *i32 (null-ptr)
``` ```
#### `<T>::is_null(val: T) -> bool` #### `<T>::alloca(size: u64) -> *T`
Returns a boolean representing if `val` is a nullptr or not. Allocates `T::sizeof() * size` bits and returns a pointer to `T`.
**Note:** This does not seem to work correctly currently.
```rust ```rust
i32::is_null(i32::null()); // Returns true i32::alloca(30); // Returns *i32
``` ```
#### `<T>::malloc(size: u64) -> *T`
Allocates `T::sizeof() * size` bytes and returns a pointer to `T`.
```rust
i32::malloc(30); // Returns *i32
// Equivalent to
malloc(i32::sizeof() * 30) as *i32
```
#### `<T>::memcpy(destination: *T, source: *T, size: u64)`
Copies `T::sizeof() * size` bytes from pointer `source` to pointer
`destination`.
```rust
let a = i32::malloc(30);
let b = i32::malloc(30);
// Copies the contents from b to a
i32::memcpy(a, b, 30);
```
#### `<T>::min(a: T, b: T) -> T`
*Note: (only on integer- and floating-point values)*
Returns the smaller of `a` and `b`.
#### `<T>::max(a: T, b: T) -> T`
*Note: (only on integer- and floating-point values)*
Returns the larger of `a` and `b`.
#### `<T>::abs(value: T) -> T`
*Note: (only on signed integer and floating-point values)*
Returns the absolute value of `value`.
#### `<T>::sqrt(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates the square-root of `value`
#### `<T>::pow(value: T, exponent: T) -> T`
*Note: (only on floating-point numbers)*
Returns `value` raised to the exponent of `exponent`.
#### `<T>::powi(value: T, exponent: u64) -> T`
*Note: (only on floating-point numbers)*
Returns `value` raised to the exponent of `exponent`.
#### `<T>::sin(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates sine of `value`
#### `<T>::cos(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates cosine of `value`
#### `<T>::tan(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates tangent of `value`
#### `<T>::asin(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates arcsine of `value`
#### `<T>::acos(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates arccosine of `value`
#### `<T>::atan(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates arctangent of `value`
#### `<T>::atan2(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates 2-argument arctangent of `value`
#### `<T>::sinh(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates hyperbolic sine of `value`
#### `<T>::cosh(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates hyperbolic cosine of `value`
#### `<T>::tanh(value: T) -> T`
*Note: (only on floating-point numbers)*
Calculates hyperbolic tangent of `value`
#### `<T>::log(value: T) -> T`
*Note: (only on floating-point numbers)*
Returns logₑ of `value`
#### `<T>::log2(value: T) -> T`
*Note: (only on floating-point numbers)*
Returns log₂ of `value`
#### `<T>::log10(value: T) -> T`
*Note: (only on floating-point numbers)*
Returns log₁₀ of `value`
#### `<T>::round(value: T) -> T`
*Note: (only on floating-point numbers)*
Rounds `value` to the nearest integer
#### `<T>::trunc(value: T) -> T`
*Note: (only on floating-point numbers)*
Truncates `value` to the integer nearest to `0`.
#### `<T>::ceil(value: T) -> T`
*Note: (only on floating-point numbers)*
Rounds `value` towards positive infinity.
#### `<T>::floor(value: T) -> T`
*Note: (only on floating-point numbers)*
Rounds `value` towards negative infinity.
#### `<T>::even(value: T) -> T`
*Note: (only on floating-point numbers)*
Rounds `value` to the closest even integer.

View File

@ -64,6 +64,10 @@ _deprecated: Use `String::concat()`_
## General ## General
#### `pub fn allocate(size: u64) -> *u8`
Unsafely allocates `size` bytes of memory from the stack, and returns a pointer to it, which must be manually freed.
## Maths ## Maths
#### `pub fn clamp(min: f32, max: f32, value: f32) -> f32` #### `pub fn clamp(min: f32, max: f32, value: f32) -> f32`

6
examples/a.reid Normal file
View File

@ -0,0 +1,6 @@
pub fn main() -> u32 {
let b = 4;
let c = b + 4;
return c;
}

View File

@ -2,14 +2,11 @@ import std::print;
import std::from_str; import std::from_str;
import std::String; import std::String;
/// Asd
struct Otus { struct Otus {
field: u32, field: u32,
} }
impl Otus { impl Otus {
/// Some test documentation here.
/// On a second line
fn test(&self) -> u32 { fn test(&self) -> u32 {
*self.field *self.field
} }
@ -21,20 +18,14 @@ impl i32 {
} }
} }
/// Hello there!
fn test() {
}
fn main() -> u32 { fn main() -> u32 {
let otus = Otus { field: 17 }; let otus = Otus { field: 17 };
print(from_str("otus: ") + Otus::test(&otus) as u64); print(from_str("otus: ") + Otus::test(&otus) as u64);
print(from_str("i32: ") + i32::test(54) as u64); print(from_str("i32: ") + i32::test(54) as u64);
print(from_str("sizeof i32: ") + i32::sizeof()); print(from_str("sizeof i32: ") + i32::sizeof());
let nullptr = i32::null(); let nullptr = i32::null();
let mut list = u64::malloc(15); let mut list = u64::alloca(15);
list[4] = 17; list[4] = 17;
print(from_str("value: ") + list[4]); print(from_str("value: ") + list[4]);

View File

@ -22,8 +22,6 @@ fn main() -> u32 {
let otus = Otus { field: 17 }; let otus = Otus { field: 17 };
print(from_str("otus: ") + otus.test() as u64); print(from_str("otus: ") + otus.test() as u64);
otus.field;
return otus.test(); return otus.test();
} }

View File

@ -1,6 +1,5 @@
// Arithmetic, function calls and imports! // Arithmetic, function calls and imports!
/// Test stuff
fn changer(param: &mut u32) { fn changer(param: &mut u32) {
*param = 17; *param = 17;
} }

6
examples/breaking.reid Normal file
View File

@ -0,0 +1,6 @@
import std::String;
import std::print;
fn main() {
print(String::new() + "hello")
}

View File

@ -1,5 +1,6 @@
// Arithmetic, function calls and imports! // Arithmetic, function calls and imports!
import std::allocate;
import std::print; import std::print;
fn other() -> i16 { fn other() -> i16 {
@ -8,7 +9,7 @@ fn other() -> i16 {
fn main() -> u32 { fn main() -> u32 {
let mut v = (malloc(4) as *u32); let mut v = (allocate(4) as *u32);
v[0] = other() as u32; v[0] = other() as u32;
return v[0]; return v[0];

View File

@ -1,10 +0,0 @@
import complicated_imported::Foo;
import complicated_imported::A;
import complicated_imported::AResult;
fn main() -> i32 {
let foo = Foo {};
let a = A::new();
foo.foo(&a.a);
return 0;
}

View File

@ -1,12 +0,0 @@
struct A {}
struct AResult { a: A }
impl A {
pub fn new() -> AResult {
AResult { a: A {} }
}
}
struct Foo {}
impl Foo {
pub fn foo(&self, a: &A) {}
}

View File

@ -1,466 +0,0 @@
// First half of Ray Tracing in One Weekend, rendered to a SDL3 window rather
// than an image file. Needs to be linked against SDL3, i.e.
// `./cli cpu_raytracer.reid SDL3`
import std::print;
import std::String;
///////////////////
/// 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 = String::new();
message = message + context + ": " + SDL_GetError();
print(message);
message.free();
}
/////////////////////////////////
/// 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_Window::null();
let mut renderer = SDL_Renderer::null();
let gfx_init_success = SDL_CreateWindowAndRenderer(
"cpu raytracer", 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 = 128;
let height = 64;
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 { type: 0, reserved: [0; 124] };
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 = String::new();
title = title + "cpu raytracer (" + *game_state.frame_counter as u64 + " fps)";
SDL_SetWindowTitle(*game_state.window, title.inner);
title.free();
*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 = 8;
let old_sample_weight = 0.9;
let new_sample_weight = 0.1 / 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,
}
impl Hit {
fn none() -> Hit {
Hit {
hit: false, front_face: true, distance: 0.0, normal: [0.0; 3], position: [0.0; 3],
material: Material { type: 0, linear_color: [0.0; 3] },
}
}
}
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,
-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 mut closest_hit = Hit::none();
closest_hit.distance = 100.0;
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::none();
}
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::none();
}
}
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(-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 * -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

@ -1,6 +0,0 @@
import foreign_struct::Vec2;
fn main() -> u32 {
let a = Vec2 {x: 16, y: 32};
return a.x;
}

View File

@ -1 +0,0 @@
struct Vec2 { x: u32, y: u32 }

View File

@ -1,9 +0,0 @@
fn main() -> i32 {
for i in 0..1 {
let j = i;
if i != j {
return 1;
}
}
return 0;
}

View File

@ -1,9 +0,0 @@
import std::String;
import std::print;
fn main() -> u8 {
let bytes = include_bytes!("./macro_easy_file.txt");
print(String::new() + bytes.length());
print(String::new() + (include_bytes!("./macro_easy_file.txt") as *u8)[1] as u64);
return (include_bytes!("./macro_easy_file.txt") as *u8)[0];
}

View File

@ -1 +0,0 @@
hello

View File

@ -1,15 +0,0 @@
extern fn printf(message: *char, num: f64);
fn main() -> i32 {
let b = 5;
let mut otus = i32::malloc(1);
otus[0] = 10500300;
let potus = i32::malloc(1);
i32::memcpy(potus, otus, 1);
printf("log10 %f\n", f64::round(123.3) as f64);
printf("sqrt %f\n", f64::sqrt(2) as f64);
printf("log10 %f\n", potus[0] as f64);
return potus[0];
}

View File

@ -1,8 +0,0 @@
struct Otus {
field: u32,
}
pub fn test() -> Otus {
Otus {field: 4}
}

View File

@ -1,11 +0,0 @@
// Arithmetic, function calls and imports!
import module_importee::Otus;
import module_importee::test;
fn main() -> u32 {
let value = 0b110;
let other = 0o17;
return value * other + test().field * -value;
}

View File

@ -1,25 +0,0 @@
struct Game {}
impl Game {
pub fn run_frame(&mut self) {}
}
struct Platform {
game: Game,
}
impl Platform {
pub fn new() -> Platform {
return Platform { game: Game {} };
}
pub fn run_frame(&mut self) {
*self.game.run_frame();
}
}
fn main() -> i32 {
let mut platform = Platform::new();
platform.run_frame();
return 0;
}

View File

@ -1,4 +0,0 @@
fn main() -> bool {
let ptr = i32::null();
return i32::is_null(ptr);
}

View File

@ -1,7 +1,9 @@
// Arithmetic, function calls and imports! // Arithmetic, function calls and imports!
import std::allocate;
fn main() -> u8 { fn main() -> u8 {
let mut ptr = u8::malloc(4); let mut ptr = allocate(4);
ptr[0] = 5; ptr[0] = 5;

View File

@ -16,7 +16,7 @@ BINARY="$(echo $1 | cut -d'.' -f1)"".out"
echo $1 echo $1
cargo run -p reid -- $@ && \ cargo run --example cli $@ && \
./$BINARY ; echo "Return value: ""$?" ./$BINARY ; echo "Return value: ""$?"
## Command from: clang -v hello.o -o test ## Command from: clang -v hello.o -o test

@ -1 +0,0 @@
Subproject commit 100cd96a6dc3bb882ce60e78c4eab47e77fdd8c4

12
reid-llvm-lib/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "reid-lib"
version = "1.0.0-beta.2"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
## LLVM Bindings
llvm-sys = {version ="201.0.1" }
## Make it easier to generate errors
thiserror = "1.0.44"

View File

@ -0,0 +1,65 @@
use reid_lib::{CmpPredicate, ConstValue, Context, FunctionFlags, Instr, TerminatorKind, Type};
fn main() {
use ConstValue::*;
use Instr::*;
let context = Context::new("libtest");
let module = context.module("test", true);
let main = module.function("main", Type::I32, Vec::new(), FunctionFlags::default());
let mut m_entry = main.block("entry");
let fibonacci = module.function(
"fibonacci",
Type::I32,
vec![Type::I32],
FunctionFlags::default(),
);
let arg = m_entry.build_named("const", Constant(I32(5))).unwrap();
let fibonacci_call = m_entry
.build_named("const", FunctionCall(fibonacci.value(), vec![arg]))
.unwrap();
m_entry
.terminate(TerminatorKind::Ret(fibonacci_call))
.unwrap();
let mut f_entry = fibonacci.block("entry");
let num_3 = f_entry.build_named("const", Constant(I32(3))).unwrap();
let param_n = f_entry.build_named("param", Param(0)).unwrap();
let cond = f_entry
.build_named("cmp", ICmp(CmpPredicate::LT, param_n, num_3))
.unwrap();
let mut then_b = fibonacci.block("then");
let mut else_b = fibonacci.block("else");
f_entry
.terminate(TerminatorKind::CondBr(cond, then_b.value(), else_b.value()))
.unwrap();
let ret_const = then_b.build_named("const", Constant(I32(1))).unwrap();
then_b.terminate(TerminatorKind::Ret(ret_const)).unwrap();
let const_1 = else_b.build_named("const", Constant(I32(1))).unwrap();
let const_2 = else_b.build_named("const", Constant(I32(2))).unwrap();
let param_1 = else_b.build_named("sub", Sub(param_n, const_1)).unwrap();
let param_2 = else_b.build_named("sub", Sub(param_n, const_2)).unwrap();
let call_1 = else_b
.build_named("fibonacci", FunctionCall(fibonacci.value(), vec![param_1]))
.unwrap();
let call_2 = else_b
.build_named("fibonacci", FunctionCall(fibonacci.value(), vec![param_2]))
.unwrap();
let add = else_b.build_named("add", Add(call_1, call_2)).unwrap();
else_b.terminate(TerminatorKind::Ret(add)).unwrap();
dbg!(&context);
context.compile(None, Vec::new());
}

View File

@ -0,0 +1,720 @@
//! This module contains simply [`Builder`] and it's related utility Values.
//! Builder is the actual struct being modified when building the LLIR.
use std::{cell::RefCell, rc::Rc};
use crate::{
Block, BlockData, CompileResult, CustomTypeKind, ErrorKind, FunctionData, Instr, InstructionData, ModuleData,
NamedStruct, TerminatorKind, Type, TypeCategory, TypeData,
debug_information::{
DebugInformation, DebugLocationValue, DebugMetadataValue, DebugScopeValue, InstructionDebugRecordData,
},
util::match_types,
};
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
pub struct ModuleValue(pub(crate) usize);
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
pub struct TypeValue(pub(crate) ModuleValue, pub(crate) usize);
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
pub struct FunctionValue(pub(crate) ModuleValue, pub(crate) usize);
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
pub struct BlockValue(pub(crate) FunctionValue, pub(crate) usize);
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
pub struct InstructionValue(pub(crate) BlockValue, pub(crate) usize);
#[derive(Clone)]
pub struct ModuleHolder {
pub(crate) value: ModuleValue,
pub(crate) data: ModuleData,
pub(crate) functions: Vec<FunctionHolder>,
pub(crate) types: Vec<TypeHolder>,
pub(crate) debug_information: Option<DebugInformation>,
}
#[derive(Clone)]
pub struct TypeHolder {
pub(crate) value: TypeValue,
pub(crate) data: TypeData,
}
#[derive(Clone)]
pub struct FunctionHolder {
pub(crate) value: FunctionValue,
pub(crate) data: FunctionData,
pub(crate) blocks: Vec<BlockHolder>,
/// Debug scope value of this current function
pub(crate) debug_info: Option<DebugScopeValue>,
}
#[derive(Clone)]
pub struct BlockHolder {
pub(crate) value: BlockValue,
pub(crate) data: BlockData,
pub(crate) instructions: Vec<InstructionHolder>,
}
#[derive(Clone)]
pub struct InstructionHolder {
pub(crate) value: InstructionValue,
pub(crate) data: InstructionData,
pub(crate) name: String,
pub(crate) record: Option<InstructionDebugRecordData>,
}
#[derive(Clone)]
pub(crate) struct Builder {
pub(crate) modules: Rc<RefCell<Vec<ModuleHolder>>>,
pub(crate) producer: String,
}
impl Builder {
pub fn new(producer: String) -> Builder {
Builder {
modules: Rc::new(RefCell::new(Vec::new())),
producer,
}
}
pub(crate) fn add_module(&self, data: ModuleData) -> ModuleValue {
let value = ModuleValue(self.modules.borrow().len());
self.modules.borrow_mut().push(ModuleHolder {
value,
data,
functions: Vec::new(),
types: Vec::new(),
debug_information: None,
});
value
}
pub(crate) fn set_debug_information(&self, mod_val: &ModuleValue, debug_info: DebugInformation) {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(mod_val.0);
module.debug_information = Some(debug_info);
}
}
pub(crate) unsafe fn add_type(&self, mod_val: &ModuleValue, data: TypeData) -> TypeValue {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(mod_val.0);
let value = TypeValue(module.value, module.types.len());
module.types.push(TypeHolder { value, data });
value
}
}
pub(crate) unsafe fn add_function(&self, mod_val: &ModuleValue, data: FunctionData) -> FunctionValue {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(mod_val.0);
let value = FunctionValue(module.value, module.functions.len());
module.functions.push(FunctionHolder {
value,
data,
blocks: Vec::new(),
debug_info: None,
});
value
}
}
pub(crate) unsafe fn add_block(&self, fun_val: &FunctionValue, data: BlockData) -> BlockValue {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(fun_val.0.0);
let function = module.functions.get_unchecked_mut(fun_val.1);
let value = BlockValue(function.value, function.blocks.len());
function.blocks.push(BlockHolder {
value,
data,
instructions: Vec::new(),
});
value
}
}
pub(crate) unsafe fn add_instruction(
&self,
block_val: &BlockValue,
data: InstructionData,
name: String,
) -> CompileResult<InstructionValue> {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(block_val.0.0.0);
let function = module.functions.get_unchecked_mut(block_val.0.1);
let block = function.blocks.get_unchecked_mut(block_val.1);
let value = InstructionValue(block.value, block.instructions.len());
block.instructions.push(InstructionHolder {
value,
data,
name,
record: None,
});
// Drop modules so that it is no longer mutable borrowed
// (check_instruction requires an immutable borrow).
drop(modules);
self.check_instruction(&value)?;
Ok(value)
}
}
pub(crate) unsafe fn add_instruction_location(&self, value: &InstructionValue, location: DebugLocationValue) {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(value.0.0.0.0);
let function = module.functions.get_unchecked_mut(value.0.0.1);
let block = function.blocks.get_unchecked_mut(value.0.1);
let instr = block.instructions.get_unchecked_mut(value.1);
instr.data.location = Some(location)
}
}
pub(crate) unsafe fn add_instruction_metadata(&self, value: &InstructionValue, metadata: DebugMetadataValue) {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(value.0.0.0.0);
let function = module.functions.get_unchecked_mut(value.0.0.1);
let block = function.blocks.get_unchecked_mut(value.0.1);
let instr = block.instructions.get_unchecked_mut(value.1);
instr.data.meta = Some(metadata)
}
}
pub(crate) unsafe fn add_instruction_record(&self, value: &InstructionValue, record: InstructionDebugRecordData) {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(value.0.0.0.0);
let function = module.functions.get_unchecked_mut(value.0.0.1);
let block = function.blocks.get_unchecked_mut(value.0.1);
let instr = block.instructions.get_unchecked_mut(value.1);
instr.record = Some(record)
}
}
pub(crate) unsafe fn set_debug_subprogram(&self, value: &FunctionValue, subprogram: DebugScopeValue) {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(value.0.0);
let function = module.functions.get_unchecked_mut(value.1);
function.debug_info = Some(subprogram)
}
}
pub(crate) unsafe fn terminate(&self, block: &BlockValue, value: TerminatorKind) -> CompileResult<()> {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(block.0.0.0);
let function = module.functions.get_unchecked_mut(block.0.1);
let block = function.blocks.get_unchecked_mut(block.1);
if let Some(_) = &block.data.terminator {
Err(ErrorKind::Null)
} else {
block.data.terminator = Some(value);
Ok(())
}
}
}
pub(crate) unsafe fn set_terminator_location(
&self,
block: &BlockValue,
location: DebugLocationValue,
) -> CompileResult<()> {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(block.0.0.0);
let function = module.functions.get_unchecked_mut(block.0.1);
let block = function.blocks.get_unchecked_mut(block.1);
if let Some(_) = &block.data.terminator_location {
Err(ErrorKind::Null)
} else {
block.data.terminator_location = Some(location);
Ok(())
}
}
}
pub(crate) unsafe fn delete_block(&self, block: &BlockValue) -> CompileResult<()> {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(block.0.0.0);
let function = module.functions.get_unchecked_mut(block.0.1);
let block = function.blocks.get_unchecked_mut(block.1);
block.data.deleted = true;
Ok(())
}
}
#[allow(dead_code)]
pub(crate) unsafe fn module_data(&self, value: &ModuleValue) -> ModuleData {
unsafe { self.modules.borrow().get_unchecked(value.0).data.clone() }
}
pub(crate) unsafe fn function_data(&self, value: &FunctionValue) -> FunctionData {
unsafe {
self.modules
.borrow()
.get_unchecked(value.0.0)
.functions
.get_unchecked(value.1)
.data
.clone()
}
}
#[allow(dead_code)]
pub(crate) unsafe fn block_data(&self, value: &BlockValue) -> BlockData {
unsafe {
self.modules
.borrow()
.get_unchecked(value.0.0.0)
.functions
.get_unchecked(value.0.1)
.blocks
.get_unchecked(value.1)
.data
.clone()
}
}
pub(crate) unsafe fn instr_data(&self, value: &InstructionValue) -> InstructionData {
unsafe {
self.modules
.borrow()
.get_unchecked(value.0.0.0.0)
.functions
.get_unchecked(value.0.0.1)
.blocks
.get_unchecked(value.0.1)
.instructions
.get_unchecked(value.1)
.data
.clone()
}
}
pub(crate) unsafe fn type_data(&self, value: &TypeValue) -> TypeData {
unsafe {
self.modules
.borrow()
.get_unchecked(value.0.0)
.types
.get_unchecked(value.1)
.data
.clone()
}
}
pub(crate) fn find_module<'ctx>(&'ctx self, value: ModuleValue) -> ModuleHolder {
unsafe { self.modules.borrow().get_unchecked(value.0).clone() }
}
pub(crate) fn get_modules(&self) -> Rc<RefCell<Vec<ModuleHolder>>> {
self.modules.clone()
}
pub fn check_instruction(&self, instruction: &InstructionValue) -> CompileResult<()> {
unsafe {
match self.instr_data(&instruction).kind {
Instr::Param(_) => Ok(()),
Instr::Constant(_) => Ok(()),
Instr::Add(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category().integer() {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::FAdd(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::Sub(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category().integer() {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::FSub(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::Mul(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category().integer() {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::FMul(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::UDiv(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::UnsignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::SDiv(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::SignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::FDiv(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::URem(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::UnsignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::SRem(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::SignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::FRem(lhs, rhs) => {
if match_types(&lhs, &rhs, &self)?.category() == TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::And(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()),
Instr::Or(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()),
Instr::XOr(lhs, rhs) => match_types(&lhs, &rhs, &self).map(|_| ()),
Instr::ICmp(_, lhs, rhs) => {
let t = match_types(&lhs, &rhs, self)?;
if t.category().comparable() || !t.category().integer() {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: Types not comparable
}
}
Instr::FCmp(_, lhs, rhs) => {
let t = match_types(&lhs, &rhs, self)?;
if t.category().comparable() || t.category() != TypeCategory::Real {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: Types not comparable
}
}
Instr::FunctionCall(fun, params) => {
let param_types = self.function_data(&fun).params;
if param_types.len() != params.len() {
return Err(ErrorKind::Null); // TODO error: invalid amount of params
}
for (a, b) in param_types.iter().zip(params) {
if *a != b.get_type(&self)? {
return Err(ErrorKind::Null); // TODO error: params do not match
}
}
Ok(())
}
Instr::Phi(vals) => {
let mut iter = vals.iter();
// TODO error: Phi must contain at least one item
// TODO error: compile can actually crash here if any of the
// incoming values come from blocks that are added later
// than the one where this one exists.
let first = iter.next().ok_or(ErrorKind::Null)?;
for item in iter {
match_types(first, item, &self)?;
}
Ok(())
}
Instr::Alloca(_) => Ok(()),
Instr::Load(ptr, load_ty) => {
let ptr_ty = ptr.get_type(&self)?;
if let Type::Ptr(ptr_ty_inner) = ptr_ty {
if *ptr_ty_inner == load_ty {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: inner type mismatch
}
} else {
Err(ErrorKind::Null) // TODO error: not a pointer
}
}
Instr::Store(ptr, _) => {
let ty = ptr.get_type(&self)?;
if let Type::Ptr(_) = ty {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: not a pointer
}
}
Instr::ArrayAlloca(_, val) => {
if val.get_type(self)?.category() == TypeCategory::UnsignedInteger {
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: not a pointer
}
}
Instr::GetElemPtr(ptr_val, _) => {
let ptr_ty = ptr_val.get_type(&self)?;
match ptr_ty {
Type::Ptr(_) => Ok(()),
_ => Err(ErrorKind::Null),
}
}
Instr::GetStructElemPtr(ptr_val, idx) => {
let ptr_ty = ptr_val.get_type(&self)?;
if let Type::Ptr(ty) = ptr_ty {
if let Type::CustomType(val) = *ty {
match self.type_data(&val).kind {
CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => {
if fields.len() <= idx as usize {
return Err(ErrorKind::Null); // TODO error: no such field
}
}
}
Ok(())
} else {
Err(ErrorKind::Null) // TODO error: not a struct
}
} else {
Err(ErrorKind::Null) // TODO error: not a pointer
}
}
Instr::ExtractValue(val, _) => {
let val_ty = val.get_type(&self)?;
match val_ty {
Type::CustomType(custom) => match self.type_data(&custom).kind {
CustomTypeKind::NamedStruct(_) => Ok(()),
},
Type::Array(_, _) => Ok(()),
_ => Err(ErrorKind::Null),
}
}
Instr::Trunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::ZExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::SExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::FPTrunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::FPExt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::FPToUI(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::FPToSI(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::UIToFP(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::SIToFP(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::PtrToInt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::IntToPtr(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
Instr::BitCast(..) => Ok(()),
Instr::ShiftRightLogical(_, rhs) => {
let rhs_ty = rhs.get_type(&self)?;
if rhs_ty.category() == TypeCategory::UnsignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::ShiftRightArithmetic(_, rhs) => {
let rhs_ty = rhs.get_type(&self)?;
if rhs_ty.category() == TypeCategory::UnsignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
Instr::ShiftLeft(_, rhs) => {
let rhs_ty = rhs.get_type(&self)?;
if rhs_ty.category() == TypeCategory::UnsignedInteger {
Ok(())
} else {
Err(ErrorKind::Null)
}
}
}
}
}
pub fn is_block_used(&self, block_v: BlockValue) -> bool {
unsafe {
let modules = self.modules.borrow();
let module = modules.get_unchecked(block_v.0.0.0);
let function = module.functions.get_unchecked(block_v.0.1);
let block = function.blocks.get_unchecked(block_v.1);
if block.instructions.len() > 0 || block.data.terminator.is_some() {
return true;
}
for other in &function.blocks {
if let Some(term) = &other.data.terminator {
match term {
TerminatorKind::Ret(_) => {}
TerminatorKind::RetVoid => {}
TerminatorKind::Br(other_val) => {
if other_val == &block_v {
return true;
}
}
TerminatorKind::CondBr(_, then_other_v, else_other_v) => {
if then_other_v == &block_v || else_other_v == &block_v {
return true;
}
}
}
}
}
false
}
}
}
impl InstructionValue {
pub fn with_location(self, block: &Block, location: DebugLocationValue) -> InstructionValue {
unsafe {
block.builder.add_instruction_location(&self, location);
}
self
}
pub fn maybe_location(self, block: &mut Block, location: Option<DebugLocationValue>) -> InstructionValue {
unsafe {
if let Some(location) = location {
block.builder.add_instruction_location(&self, location);
}
}
self
}
pub fn add_record(&self, block: &mut Block, record: InstructionDebugRecordData) {
unsafe {
block.builder.add_instruction_record(self, record);
}
}
pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult<Type> {
use Instr::*;
unsafe {
match &builder.instr_data(self).kind {
Param(nth) => builder
.function_data(&self.0.0)
.params
.get(*nth)
.cloned()
.ok_or(ErrorKind::Null),
Constant(c) => Ok(c.get_type()),
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
FAdd(lhs, rhs) => match_types(lhs, rhs, &builder),
Sub(lhs, rhs) => match_types(lhs, rhs, &builder),
FSub(lhs, rhs) => match_types(lhs, rhs, &builder),
Mul(lhs, rhs) => match_types(lhs, rhs, &builder),
FMul(lhs, rhs) => match_types(lhs, rhs, &builder),
UDiv(lhs, rhs) => match_types(lhs, rhs, &builder),
SDiv(lhs, rhs) => match_types(lhs, rhs, &builder),
FDiv(lhs, rhs) => match_types(lhs, rhs, &builder),
URem(lhs, rhs) => match_types(lhs, rhs, &builder),
SRem(lhs, rhs) => match_types(lhs, rhs, &builder),
FRem(lhs, rhs) => match_types(lhs, rhs, &builder),
And(lhs, rhs) => match_types(lhs, rhs, &builder),
Or(lhs, rhs) => match_types(lhs, rhs, &builder),
XOr(lhs, rhs) => match_types(lhs, rhs, &builder),
ICmp(_, _, _) => Ok(Type::Bool),
FCmp(_, _, _) => Ok(Type::Bool),
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
Phi(values) => values.first().ok_or(ErrorKind::Null).and_then(|v| v.get_type(&builder)),
Alloca(ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
Load(_, ty) => Ok(ty.clone()),
Store(_, value) => value.get_type(builder),
ArrayAlloca(ty, _) => Ok(Type::Ptr(Box::new(ty.clone()))),
GetElemPtr(instr, _) => {
let instr_ty = instr.get_type(builder)?;
let Type::Ptr(inner_ty) = &instr_ty else {
panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty)
};
match *inner_ty.clone() {
Type::Array(elem_ty, _) => Ok(Type::Ptr(Box::new(*elem_ty.clone()))),
_ => Ok(instr_ty),
}
}
GetStructElemPtr(instr, idx) => {
let instr_ty = instr.get_type(builder)?;
let Type::Ptr(inner_ty) = instr_ty else {
panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty)
};
let Type::CustomType(ty_value) = *inner_ty else {
panic!("GetStructElemPtr on non-struct! ({:?})", &inner_ty)
};
let field_ty = match builder.type_data(&ty_value).kind {
CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => {
fields.get_unchecked(*idx as usize).clone()
}
};
Ok(Type::Ptr(Box::new(field_ty)))
}
ExtractValue(instr, idx) => {
let instr_ty = instr.get_type(builder)?;
Ok(match instr_ty {
Type::CustomType(struct_ty) => {
let data = builder.type_data(&struct_ty);
match data.kind {
CustomTypeKind::NamedStruct(named_struct) => {
named_struct.1.get(*idx as usize).unwrap().clone()
}
}
}
Type::Array(elem_ty, _) => *elem_ty.clone(),
_ => return Err(ErrorKind::Null),
})
}
Trunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
ZExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
SExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
FPTrunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
FPExt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
FPToUI(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
FPToSI(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
UIToFP(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
SIToFP(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
PtrToInt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
IntToPtr(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
BitCast(_, ty) => Ok(ty.clone()),
ShiftRightLogical(lhs, _) => lhs.get_type(builder),
ShiftRightArithmetic(lhs, _) => lhs.get_type(builder),
ShiftLeft(lhs, _) => lhs.get_type(builder),
}
}
}
fn cast_to(&self, builder: &Builder, ty: &Type) -> CompileResult<Instr> {
self.get_type(builder)?
.cast_instruction(*self, &ty)
.ok_or(ErrorKind::Null)
}
}

1202
reid-llvm-lib/src/compile.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,402 @@
use std::{
cell::{Ref, RefCell, RefMut},
rc::Rc,
};
use crate::builder::InstructionValue;
/// Represents 1. the compilation context, 2. subprogram or 3. a lexical scope
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct DebugScopeValue(pub Vec<usize>);
#[derive(Clone, Hash, PartialEq, Eq)]
pub struct DebugLocationValue(pub DebugScopeValue, pub usize);
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugTypeValue(pub usize);
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct DebugMetadataValue(pub usize);
#[derive(Debug, Clone)]
pub struct DebugFileData {
pub name: String,
pub directory: String,
}
#[derive(Debug, Clone)]
pub(crate) struct DebugScopeHolder {
pub(crate) value: DebugScopeValue,
pub(crate) data: DebugScopeData,
pub(crate) inner_scopes: Vec<DebugScopeHolder>,
}
#[derive(Debug, Clone)]
pub struct DebugMetadataHolder {
pub(crate) location: DebugLocation,
pub(crate) value: DebugMetadataValue,
pub(crate) data: DebugMetadata,
}
#[derive(Clone)]
pub struct DebugTypeHolder {
pub(crate) value: DebugTypeValue,
pub(crate) data: DebugTypeData,
}
#[derive(Debug, Clone)]
pub(crate) struct DebugLocationHolder {
pub(crate) scope: DebugScopeValue,
pub(crate) value: DebugLocationValue,
pub(crate) location: DebugLocation,
}
#[derive(Debug, Clone)]
pub struct DebugInformation {
pub file: DebugFileData,
scope: Rc<RefCell<DebugScopeHolder>>,
locations: Rc<RefCell<Vec<DebugLocationHolder>>>,
metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>,
types: Rc<RefCell<Vec<DebugTypeHolder>>>,
}
impl DebugInformation {
pub fn from_file(file: DebugFileData) -> (DebugInformation, DebugScopeValue) {
let scope_value = DebugScopeValue(Vec::new());
(
DebugInformation {
file,
scope: Rc::new(RefCell::new(DebugScopeHolder {
value: scope_value.clone(),
inner_scopes: Vec::new(),
data: DebugScopeData {
parent: None,
location: Some(DebugLocation {
scope: DebugScopeValue(Vec::new()),
pos: DebugPosition { line: 0, column: 0 },
}),
kind: DebugScopeKind::CodegenContext,
},
})),
locations: Rc::new(RefCell::new(Vec::new())),
metadata: Rc::new(RefCell::new(Vec::new())),
types: Rc::new(RefCell::new(Vec::new())),
},
scope_value,
)
}
pub fn inner_scope(&self, parent: &DebugScopeValue, location: DebugLocation) -> DebugScopeValue {
unsafe {
let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| {
for i in &parent.0 {
v = v.inner_scopes.get_unchecked_mut(*i);
}
v
});
let mut arr = parent.0.clone();
arr.push(parent.0.len());
let value = DebugScopeValue(arr);
outer_scope.inner_scopes.push(DebugScopeHolder {
value: value.clone(),
inner_scopes: Vec::new(),
data: DebugScopeData {
parent: Some(parent.clone()),
location: Some(location),
kind: DebugScopeKind::LexicalScope,
},
});
value
}
}
pub fn location(&self, scope_value: &DebugScopeValue, location: DebugLocation) -> DebugLocationValue {
let value = DebugLocationValue(scope_value.clone(), self.locations.borrow().len());
let location = DebugLocationHolder {
scope: scope_value.clone(),
value: value.clone(),
location,
};
self.locations.borrow_mut().push(location);
value
}
pub fn debug_type(&self, kind: DebugTypeData) -> DebugTypeValue {
let mut types = self.types.borrow_mut();
let value = DebugTypeValue(types.len());
types.push(DebugTypeHolder {
value: value.clone(),
data: kind,
});
value
}
pub fn metadata(&self, location: &DebugLocation, kind: DebugMetadata) -> DebugMetadataValue {
let mut metadata = self.metadata.borrow_mut();
let value = DebugMetadataValue(metadata.len());
metadata.push(DebugMetadataHolder {
location: location.clone(),
value: value.clone(),
data: kind,
});
value
}
pub fn subprogram(&self, parent: DebugScopeValue, kind: DebugSubprogramData) -> DebugScopeValue {
unsafe {
let mut outer_scope = RefMut::map(self.scope.borrow_mut(), |mut v| {
for i in &parent.0 {
v = v.inner_scopes.get_unchecked_mut(*i);
}
v
});
let mut arr = parent.0.clone();
arr.push(outer_scope.inner_scopes.len());
let value = DebugScopeValue(arr);
outer_scope.inner_scopes.push(DebugScopeHolder {
value: value.clone(),
inner_scopes: Vec::new(),
data: DebugScopeData {
parent: Some(parent.clone()),
location: None,
kind: DebugScopeKind::Subprogram(kind),
},
});
value
}
}
pub fn get_metadata(&self, value: DebugMetadataValue) -> DebugMetadata {
unsafe { self.metadata.borrow().get_unchecked(value.0).data.clone() }
}
pub fn get_metadata_location(&self, value: DebugMetadataValue) -> DebugLocation {
unsafe { self.metadata.borrow().get_unchecked(value.0).location.clone() }
}
pub fn get_scope_data(&self, value: &DebugScopeValue) -> Option<DebugScopeData> {
let scope = Ref::filter_map(self.scope.borrow(), |v: &DebugScopeHolder| {
let mut opt = Some(v);
for i in &value.0 {
if let Some(inner) = opt {
opt = inner.inner_scopes.get(*i);
}
}
opt
});
if let Ok(scope) = scope {
Some(scope.data.clone())
} else {
None
}
}
pub fn get_type_data(&self, value: DebugTypeValue) -> DebugTypeData {
unsafe { self.types.borrow().get_unchecked(value.0).data.clone() }
}
pub fn get_location(&self, value: &DebugLocationValue) -> DebugLocation {
unsafe { self.locations.borrow().get_unchecked(value.1).location.clone() }
}
pub fn get_metadatas(&self) -> Rc<RefCell<Vec<DebugMetadataHolder>>> {
self.metadata.clone()
}
pub(crate) fn get_scope(&self) -> Rc<RefCell<DebugScopeHolder>> {
self.scope.clone()
}
pub fn get_types(&self) -> Rc<RefCell<Vec<DebugTypeHolder>>> {
self.types.clone()
}
pub(crate) fn get_locations(&self) -> Rc<RefCell<Vec<DebugLocationHolder>>> {
self.locations.clone()
}
}
#[derive(Clone)]
pub struct DebugLocation {
pub scope: DebugScopeValue,
pub pos: DebugPosition,
}
#[derive(Clone, Copy)]
pub struct DebugPosition {
pub line: u32,
pub column: u32,
}
#[derive(Debug, Clone)]
pub enum DebugMetadata {
ParamVar(DebugParamVariable),
LocalVar(DebugLocalVariable),
VarAssignment,
}
#[derive(Debug, Clone)]
pub struct DebugParamVariable {
pub name: String,
/// the index (starting from 1) of this variable in the subprogram
/// parameters. arg_idx should not conflict with other parameters of the
/// same subprogram.
pub arg_idx: u32,
pub ty: DebugTypeValue,
/// If this variable will be referenced from its containing subprogram, and
/// will survive some optimizations.
pub always_preserve: bool,
pub flags: DwarfFlags,
}
#[derive(Debug, Clone)]
pub struct DebugLocalVariable {
pub name: String,
pub ty: DebugTypeValue,
pub always_preserve: bool,
pub flags: DwarfFlags,
}
impl Default for DebugSubprogramOptionals {
fn default() -> Self {
Self {
scope_line: 0,
is_local: false,
is_definition: true,
is_optimized: false,
flags: DwarfFlags,
}
}
}
#[derive(Debug, Clone)]
pub struct DwarfFlags;
#[derive(Clone)]
pub enum DebugTypeData {
Basic(DebugBasicType),
Subprogram(DebugSubprogramType),
Pointer(DebugPointerType),
Array(DebugArrayType),
Struct(DebugStructType),
}
#[derive(Clone)]
pub struct DebugBasicType {
pub name: String,
/// Size of the type.
pub size_bits: u64,
/// DWARF encoding code, e.g., dwarf::DW_ATE_float.
pub encoding: DwarfEncoding,
/// Optional DWARF attributes, e.g., DW_AT_endianity.
pub flags: DwarfFlags,
}
#[derive(Clone)]
pub struct DebugArrayType {
pub size_bits: u64,
pub align_bits: u32,
pub element_type: DebugTypeValue,
pub length: u64,
}
#[derive(Clone)]
pub struct DebugPointerType {
pub name: String,
pub pointee: DebugTypeValue,
pub size_bits: u64,
}
#[derive(Clone)]
pub struct DebugStructType {
pub name: String,
pub scope: DebugScopeValue,
pub pos: Option<DebugPosition>,
pub size_bits: u64,
pub flags: DwarfFlags,
pub fields: Vec<DebugFieldType>,
}
#[derive(Clone)]
pub struct DebugFieldType {
pub name: String,
pub scope: DebugScopeValue,
pub pos: Option<DebugPosition>,
pub size_bits: u64,
pub offset: u64,
pub flags: DwarfFlags,
pub ty: DebugTypeValue,
}
#[derive(Clone)]
pub struct DebugSubprogramType {
pub parameters: Vec<DebugTypeValue>,
pub flags: DwarfFlags,
}
#[derive(Debug, Clone, Copy)]
pub enum DwarfEncoding {
Address = 1,
Boolean = 2,
Float = 4,
Signed = 5,
SignedChar = 6,
Unsigned = 7,
UnsignedChar = 8,
}
#[derive(Debug, Clone)]
pub struct DebugScopeData {
pub parent: Option<DebugScopeValue>,
pub location: Option<DebugLocation>,
pub kind: DebugScopeKind,
}
#[derive(Debug, Clone)]
pub enum DebugScopeKind {
CodegenContext,
LexicalScope,
Subprogram(DebugSubprogramData),
}
#[derive(Debug, Clone)]
pub struct DebugSubprogramData {
/// Function name.
pub name: String,
pub outer_scope: DebugScopeValue,
/// Used for line number.
pub location: DebugLocation,
/// Function type.
pub ty: DebugTypeValue,
pub opts: DebugSubprogramOptionals,
}
#[derive(Debug, Clone)]
pub struct DebugSubprogramOptionals {
/// Set to the beginning of the scope this starts
pub scope_line: u32,
pub is_local: bool,
pub is_definition: bool,
pub is_optimized: bool,
/// These flags are used to emit dwarf attributes. e.g. is this function
/// prototyped or not.
pub flags: DwarfFlags,
}
#[derive(Clone)]
pub struct InstructionDebugRecordData {
pub scope: DebugScopeValue,
pub variable: DebugMetadataValue,
pub location: DebugLocation,
pub kind: DebugRecordKind,
}
#[derive(Clone, Copy)]
pub enum DebugRecordKind {
Declare(InstructionValue),
Value(InstructionValue),
}

593
reid-llvm-lib/src/fmt.rs Normal file
View File

@ -0,0 +1,593 @@
//! Debug implementations for relevant types
use std::{
fmt::{Debug, Display, Write},
marker::PhantomData,
};
use crate::{
CmpPredicate, Context, Instr, InstructionData, TerminatorKind,
builder::*,
debug_information::{
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable, DebugLocation,
DebugLocationValue, DebugMetadata, DebugMetadataValue, DebugParamVariable, DebugPointerType, DebugPosition,
DebugRecordKind, DebugScopeValue, DebugStructType, DebugSubprogramType, DebugTypeData, DebugTypeHolder,
DebugTypeValue,
},
pad_adapter::PadAdapter,
};
impl Display for Context {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.builder, f)
}
}
impl Display for Builder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Producer: {}", self.producer)?;
for module in self.modules.borrow().iter() {
if module.data.is_main {
write!(f, "main ")?;
}
writeln!(f, "{} ({:?}) {{", module.data.name, module.value)?;
for function in &module.functions {
let mut state = Default::default();
let mut inner = PadAdapter::wrap(f, &mut state);
function.builder_fmt(&mut inner, self, &module.debug_information)?;
}
writeln!(f, "}}")?;
}
Ok(())
}
}
impl FunctionHolder {
fn builder_fmt(
&self,
f: &mut impl std::fmt::Write,
builder: &Builder,
debug: &Option<DebugInformation>,
) -> std::fmt::Result {
if self.data.flags.is_imported {
write!(f, "imported ")?;
}
if self.data.flags.is_extern {
write!(f, "extern ")?;
}
if self.data.flags.is_pub {
write!(f, "pub ")?;
}
if self.data.flags.is_main {
write!(f, "main ")?;
}
let params = self
.data
.params
.iter()
.map(|p| format!("{:?}", p))
.collect::<Vec<_>>()
.join(", ");
write!(f, "fn {}({}) -> {:?} ", self.data.name, params, self.data.ret)?;
writeln!(f, "{{")?;
let mut state = Default::default();
let mut inner = PadAdapter::wrap(f, &mut state);
writeln!(inner, "(Value = {:?}) ", self.value)?;
if let Some(debug) = &self.debug_info {
writeln!(inner, "(Debug = {:?})", debug)?;
}
for block in &self.blocks {
let mut state = Default::default();
let mut inner = PadAdapter::wrap(&mut inner, &mut state);
block.builder_fmt(&mut inner, builder, debug)?;
}
writeln!(f, "}}")?;
Ok(())
}
}
impl BlockHolder {
fn builder_fmt(
&self,
f: &mut impl std::fmt::Write,
builder: &Builder,
debug: &Option<DebugInformation>,
) -> std::fmt::Result {
if self.data.deleted {
write!(f, "deleted ")?;
}
writeln!(f, "{} ({:?}):", self.data.name, self.value)?;
let mut state = Default::default();
let mut inner = PadAdapter::wrap(f, &mut state);
for instr in &self.instructions {
instr.builder_fmt(&mut inner, builder, debug)?;
}
if let Some(terminator) = &self.data.terminator {
terminator.builder_fmt(&mut inner, builder, debug)?;
}
if let Some(location) = &self.data.terminator_location {
writeln!(inner, " ^ (At {}) ", debug.as_ref().unwrap().get_location(location))?;
}
Ok(())
}
}
impl InstructionHolder {
fn builder_fmt(
&self,
f: &mut impl std::fmt::Write,
_builder: &Builder,
debug: &Option<DebugInformation>,
) -> std::fmt::Result {
if let Some(record) = &self.record {
let kind = match record.kind {
DebugRecordKind::Declare(instruction_value) => {
format!("= {:?} (Assign)", instruction_value)
}
DebugRecordKind::Value(instruction_value) => {
format!("= {:?} (Value)", instruction_value)
}
};
if let Some(debug) = debug {
writeln!(f, " (Debug {} {})", record.variable.hr(debug), kind)?;
}
}
writeln!(f, "{:?} ({}) = {:?} ", self.value, self.name, self.data.kind)?;
if let Some(debug) = debug {
if let Some(location) = &self.data.location {
writeln!(f, " ^ (At {}) ", debug.get_location(location))?;
}
if let Some(meta) = self.data.meta {
writeln!(f, " ^ (Meta {}) ", meta.hr(debug))?;
}
}
writeln!(f)?;
Ok(())
}
}
impl TerminatorKind {
fn builder_fmt(
&self,
f: &mut impl std::fmt::Write,
_builder: &Builder,
_debug: &Option<DebugInformation>,
) -> std::fmt::Result {
match self {
TerminatorKind::Ret(instr) => writeln!(f, "ret {:?}", instr),
TerminatorKind::RetVoid => writeln!(f, "ret void"),
TerminatorKind::Br(block) => writeln!(f, "br {:?}", block),
TerminatorKind::CondBr(instr, lhs, rhs) => {
writeln!(f, "condbr {:?}, {:?} or {:?}", instr, lhs, rhs)
}
}
}
}
impl DebugMetadataValue {
fn hr(&self, debug: &DebugInformation) -> String {
let kind = match debug.get_metadata(*self) {
DebugMetadata::ParamVar(DebugParamVariable { name, arg_idx, ty, .. }) => {
format!("param {} (idx {}) (type {:?}) ", name, arg_idx, ty)
}
DebugMetadata::LocalVar(DebugLocalVariable { name, ty, .. }) => {
format!("var {} (type {:?}) ", name, ty)
}
DebugMetadata::VarAssignment => todo!(),
};
format!("{} at {}", kind, debug.get_metadata_location(*self))
}
}
impl Display for DebugLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?} on scope {:?}", self.pos, self.scope)
}
}
impl Display for DebugPosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "line {}, col {}", self.line, self.column)
}
}
impl Debug for Builder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.get_modules().borrow().iter());
Ok(())
}
}
pub struct PrintableModule<'ctx> {
pub phantom: PhantomData<&'ctx ()>,
pub module: ModuleHolder,
}
impl<'ctx> Debug for PrintableModule<'ctx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.module, f)
}
}
impl Debug for ModuleHolder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(&format!("{}({:#?}) ", self.data.name, self.value))
.field(&self.functions)
// .field(&self.debug_information)
.finish()
}
}
impl Debug for FunctionHolder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(&format!(
"{}({:?}) -> {:?} ",
self.data.name, self.data.params, self.data.ret
))
.field(&self.blocks)
.finish()
}
}
impl Debug for BlockHolder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let deleted = if self.data.deleted { " (deleted)" } else { "" };
f.debug_tuple(&format!("{}[{:?}]{} ", &self.data.name, &self.value, deleted))
.field(&self.instructions)
.field(&self.data.terminator)
.field(&self.data.terminator_location)
.finish()
}
}
impl Debug for InstructionHolder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value.fmt(f)?;
write!(f, " ({})", self.name)?;
f.write_str(" = ")?;
self.data.fmt(f)
}
}
impl Debug for InstructionData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.kind.fmt(f)?;
if let Some(location) = &self.location {
write!(f, " ({:?})", location)?;
}
Ok(())
}
}
impl Debug for ModuleValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "M[{:0>2}]", self.0)
}
}
impl Debug for FunctionValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "F[{:0>2}-{:0>2}]", &self.0.0, self.1)
}
}
impl Debug for BlockValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "B[{:0>2}-{:0>2}-{:0>2}]", &self.0.0.0, &self.0.1, self.1)
}
}
impl Debug for InstructionValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "%{}.{}.{}.{}", self.0.0.0.0, self.0.0.1, self.0.1, self.1)
}
}
// impl Debug for InstructionValue {
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(
// f,
// "I[{:0>2}-{:0>2}-{:0>2}-{:0>2}]",
// &self.0.0.0.0, &self.0.0.1, &self.0.1, self.1
// )
// }
// }
impl Debug for TypeValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Ty[{:0>2}-{:0>2}]", &self.0.0, self.1)
}
}
impl Debug for Instr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Instr::Param(nth) => fmt_call(f, &"Param", &nth),
Instr::Constant(c) => c.fmt(f),
Instr::Add(lhs, rhs) => fmt_binop(f, lhs, &"+", rhs),
Instr::FAdd(lhs, rhs) => fmt_binop(f, lhs, &"+", rhs),
Instr::Sub(lhs, rhs) => fmt_binop(f, lhs, &"-", rhs),
Instr::FSub(lhs, rhs) => fmt_binop(f, lhs, &"-", rhs),
Instr::Mul(lhs, rhs) => fmt_binop(f, lhs, &"*", rhs),
Instr::FMul(lhs, rhs) => fmt_binop(f, lhs, &"*", rhs),
Instr::UDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs),
Instr::SDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs),
Instr::FDiv(lhs, rhs) => fmt_binop(f, lhs, &"/", rhs),
Instr::URem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs),
Instr::SRem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs),
Instr::FRem(lhs, rhs) => fmt_binop(f, lhs, &"%", rhs),
Instr::And(lhs, rhs) => fmt_binop(f, lhs, &"&&", rhs),
Instr::Phi(val) => fmt_call(f, &"Phi", &val),
Instr::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs),
Instr::FCmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs),
Instr::FunctionCall(fun, params) => fmt_call(f, fun, params),
Instr::Alloca(ty) => write!(f, "alloca<{:?}>", ty),
Instr::Load(val, ty) => write!(f, "load<{:?}>({:?})", ty, val),
Instr::Store(ptr, val) => write!(f, "store({:?} = {:?})", ptr, val),
Instr::ArrayAlloca(ty, instruction_value) => {
write!(f, "array_alloca<{:?}>({:?})", ty, instruction_value)
}
Instr::GetElemPtr(instruction_value, items) => fmt_index(
f,
instruction_value,
&items
.iter()
.map(|expr| format!("{:?}", expr))
.collect::<Vec<_>>()
.join(", "),
),
Instr::GetStructElemPtr(instruction_value, index) => {
write!(f, "GEP(")?;
fmt_index(f, instruction_value, &index.to_string())?;
write!(f, ")")
}
Instr::ExtractValue(instruction_value, index) => fmt_index(f, instruction_value, &index.to_string()),
Instr::Trunc(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::ZExt(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::SExt(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::FPTrunc(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::FPExt(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::FPToUI(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::FPToSI(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::UIToFP(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::SIToFP(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::PtrToInt(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::IntToPtr(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::BitCast(instr_val, ty) => {
write!(f, "{:?} to {:?} ({})", instr_val, ty, self.default_name())
}
Instr::Or(lhs, rhs) => fmt_binop(f, lhs, &"||", rhs),
Instr::XOr(lhs, rhs) => fmt_binop(f, lhs, &"^", rhs),
Instr::ShiftRightLogical(lhs, rhs) => fmt_binop(f, lhs, &">>l", rhs),
Instr::ShiftRightArithmetic(lhs, rhs) => fmt_binop(f, lhs, &">>a", rhs),
Instr::ShiftLeft(lhs, rhs) => fmt_binop(f, lhs, &"<<", rhs),
}
}
}
fn fmt_binop(
f: &mut std::fmt::Formatter<'_>,
lhs: &impl std::fmt::Debug,
op: &impl std::fmt::Debug,
rhs: &impl std::fmt::Debug,
) -> std::fmt::Result {
lhs.fmt(f)?;
f.write_char(' ')?;
op.fmt(f)?;
f.write_char(' ')?;
rhs.fmt(f)
}
fn fmt_call(
f: &mut std::fmt::Formatter<'_>,
fun: &impl std::fmt::Debug,
params: &impl std::fmt::Debug,
) -> std::fmt::Result {
fun.fmt(f)?;
f.write_char('(')?;
params.fmt(f)?;
f.write_char(')')
}
fn fmt_index(
f: &mut std::fmt::Formatter<'_>,
fun: &impl std::fmt::Debug,
params: &impl std::fmt::Debug,
) -> std::fmt::Result {
fun.fmt(f)?;
f.write_char('[')?;
params.fmt(f)?;
f.write_char(']')
}
impl Debug for CmpPredicate {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LT => write!(f, "<"),
Self::GT => write!(f, ">"),
Self::LE => write!(f, "<="),
Self::GE => write!(f, ">="),
Self::EQ => write!(f, "=="),
Self::NE => write!(f, "!="),
}
}
}
impl Debug for TerminatorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Ret(val) => {
write!(f, "Ret ")?;
val.fmt(f)
}
Self::RetVoid => write!(f, "Void Ret"),
Self::Br(val) => {
write!(f, "Br ")?;
val.fmt(f)
}
Self::CondBr(cond, b1, b2) => {
write!(f, "CondBr ")?;
cond.fmt(f)?;
write!(f, " ? ")?;
b1.fmt(f)?;
write!(f, " : ")?;
b2.fmt(f)?;
Ok(())
}
}
}
}
impl Debug for DebugTypeHolder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(&format!("DebugTypeHolder {:?}", self.value))
.field(&self.data)
.finish()
}
}
impl Debug for DebugTypeData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DebugTypeData::Basic(ty) => Debug::fmt(ty, f),
DebugTypeData::Subprogram(ty) => Debug::fmt(ty, f),
DebugTypeData::Pointer(ty) => Debug::fmt(ty, f),
DebugTypeData::Array(ty) => Debug::fmt(ty, f),
DebugTypeData::Struct(ty) => Debug::fmt(ty, f),
}
}
}
impl Debug for DebugBasicType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("BasicType")
.field(&self.name)
.field(&self.size_bits)
.field(&self.encoding)
.field(&self.flags)
.finish()
}
}
impl Debug for DebugStructType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Struct")
.field("name", &self.name)
.field("scope", &self.scope)
.field("pos", &self.pos)
.field("size_bit", &self.size_bits)
.field("flags", &self.flags)
.field("elements", &self.fields)
.finish()
}
}
impl Debug for DebugFieldType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(&format!("Field({})", self.name))
.field("scope", &self.scope)
.field("pos", &self.pos)
.field("size_bits", &self.size_bits)
.field("offset", &self.offset)
.field("flags", &self.flags)
.field("ty", &self.ty)
.finish()
}
}
impl Debug for DebugSubprogramType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Subprogram")
.field(&self.parameters)
.field(&self.flags)
.finish()
}
}
impl Debug for DebugPointerType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(&format!("Pointer<{:?}>({})", self.pointee, self.name))
.field(&self.size_bits)
.finish()
}
}
impl Debug for DebugArrayType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(&format!("Array<{:?}>[{}]", self.element_type, self.length))
.field("size_bits", &self.size_bits)
.field("align_bits", &self.align_bits)
.finish()
}
}
impl Debug for DebugMetadataValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Meta[{}]", self.0)
}
}
impl Debug for DebugScopeValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Scope[{}]",
self.0.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", ")
)
}
}
impl Debug for DebugTypeValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Type[{}]", self.0)
}
}
impl Debug for DebugLocationValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Value[{:?}][{}]", self.0, self.1)
}
}
impl Debug for DebugLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?} on scope {:?}", self.pos, self.scope)
}
}
impl Debug for DebugPosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ln {}, col {}", self.line, self.column)
}
}

660
reid-llvm-lib/src/lib.rs Normal file
View File

@ -0,0 +1,660 @@
//! Reid LLVM Lib is an ergonomic Rust'y API which is used to produce a
//! Low-Level IR (LLIR) using [`Context`] and [`Builder`]. This Builder can then
//! be used at the end to compile said LLIR into LLVM IR.
use std::{fmt::Debug, marker::PhantomData};
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, TypeValue};
use debug_information::{DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue};
use fmt::PrintableModule;
use crate::debug_information::DebugScopeValue;
pub mod builder;
pub mod compile;
pub mod debug_information;
mod fmt;
mod pad_adapter;
mod util;
#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)]
pub enum ErrorKind {
#[error("NULL error, should never occur!")]
Null,
}
pub type CompileResult<T> = Result<T, ErrorKind>;
#[derive(Debug)]
pub struct Context {
builder: Builder,
}
impl Context {
pub fn new<T: Into<String>>(producer: T) -> Context {
Context {
builder: Builder::new(producer.into()),
}
}
pub fn module<'ctx>(&'ctx self, name: &str, main: bool) -> Module<'ctx> {
let value = self.builder.add_module(ModuleData {
name: name.to_owned(),
is_main: main,
});
Module {
phantom: PhantomData,
builder: self.builder.clone(),
value,
debug_info: None,
}
}
}
#[derive(Debug, Clone, Hash)]
pub struct ModuleData {
name: String,
is_main: bool,
}
#[derive(Clone)]
pub struct Module<'ctx> {
phantom: PhantomData<&'ctx ()>,
builder: Builder,
value: ModuleValue,
debug_info: Option<DebugInformation>,
}
impl<'ctx> Module<'ctx> {
pub fn function(&self, name: &str, ret: Type, params: Vec<Type>, flags: FunctionFlags) -> Function<'ctx> {
unsafe {
Function {
phantom: PhantomData,
builder: self.builder.clone(),
value: self.builder.add_function(
&self.value,
FunctionData {
name: name.to_owned(),
ret,
params,
flags,
},
),
}
}
}
pub fn custom_type(&self, ty: CustomTypeKind) -> TypeValue {
unsafe {
let (name, kind) = match &ty {
CustomTypeKind::NamedStruct(NamedStruct(name, _)) => (name.clone(), ty),
};
self.builder.add_type(&self.value, TypeData { name, kind })
}
}
pub fn value(&self) -> ModuleValue {
self.value
}
pub fn as_printable(&self) -> PrintableModule<'ctx> {
PrintableModule {
phantom: PhantomData,
module: self.builder.find_module(self.value),
}
}
pub fn create_debug_info(&mut self, file: DebugFileData) -> (DebugInformation, DebugScopeValue) {
let (debug_info, scope_value) = DebugInformation::from_file(file);
self.debug_info = Some(debug_info.clone());
(debug_info, scope_value)
}
pub fn get_debug_info(&self) -> &Option<DebugInformation> {
&self.debug_info
}
}
impl<'ctx> Drop for Module<'ctx> {
fn drop(&mut self) {
if let Some(debug_info) = self.debug_info.take() {
self.builder.set_debug_information(&self.value, debug_info);
}
}
}
#[derive(Debug, Clone, Hash)]
pub struct FunctionData {
name: String,
ret: Type,
params: Vec<Type>,
flags: FunctionFlags,
}
#[derive(Debug, Clone, Copy, Hash)]
pub struct FunctionFlags {
/// True in the destination module of the import, false in the source module.
pub is_extern: bool,
/// Whether this function is the main function of the module, that should be
/// executed (and linked externally also).
pub is_main: bool,
/// Whether this function should be available externally always.
pub is_pub: bool,
/// If this function is an imported function (either in the source or
/// destination module)
pub is_imported: bool,
/// Whether this function should add "alwaysinline"-attribute.
pub inline: bool,
}
impl Default for FunctionFlags {
fn default() -> FunctionFlags {
FunctionFlags {
is_extern: false,
is_main: false,
is_pub: false,
is_imported: false,
inline: false,
}
}
}
pub struct Function<'ctx> {
phantom: PhantomData<&'ctx ()>,
builder: Builder,
value: FunctionValue,
}
impl<'ctx> Function<'ctx> {
pub fn block(&self, name: &str) -> Block<'ctx> {
unsafe {
Block {
phantom: PhantomData,
builder: self.builder.clone(),
value: self.builder.add_block(
&self.value,
BlockData {
name: name.to_owned(),
terminator: None,
terminator_location: None,
deleted: false,
},
),
}
}
}
pub fn set_debug(&self, subprogram: DebugScopeValue) {
unsafe {
self.builder.set_debug_subprogram(&self.value, subprogram);
}
}
pub fn value(&self) -> FunctionValue {
self.value
}
}
#[derive(Debug, Clone, Hash)]
pub struct BlockData {
name: String,
terminator: Option<TerminatorKind>,
terminator_location: Option<DebugLocationValue>,
deleted: bool,
}
#[derive(Clone)]
pub struct Block<'builder> {
phantom: PhantomData<&'builder ()>,
builder: Builder,
value: BlockValue,
}
impl Instr {
pub fn default_name(&self) -> &str {
match self {
Instr::Param(_) => "param",
Instr::Constant(_) => "const1",
Instr::Add(..) => "add",
Instr::FAdd(..) => "fadd",
Instr::Sub(..) => "sub",
Instr::FSub(..) => "fsub",
Instr::Mul(..) => "mul",
Instr::FMul(..) => "fmul",
Instr::UDiv(..) => "udiv",
Instr::SDiv(..) => "sdiv",
Instr::FDiv(..) => "fdiv",
Instr::URem(..) => "urem",
Instr::SRem(..) => "srem",
Instr::FRem(..) => "frem",
Instr::And(..) => "and",
Instr::Phi(_) => "phi",
Instr::Alloca(_) => "alloca",
Instr::Load(_, _) => "load",
Instr::Store(..) => "store",
Instr::ArrayAlloca(_, _) => "arrayalloca",
Instr::GetElemPtr(..) => "getelemptr",
Instr::GetStructElemPtr(..) => "getstructelemptr",
Instr::ExtractValue(..) => "extractvalue",
Instr::ICmp(..) => "icmp",
Instr::FunctionCall(..) => "call",
Instr::FCmp(_, _, _) => "fcmp",
Instr::Trunc(_, _) => "trunc",
Instr::ZExt(_, _) => "zext",
Instr::SExt(_, _) => "sext",
Instr::FPTrunc(_, _) => "fptrunc",
Instr::FPExt(_, _) => "pfext",
Instr::FPToUI(_, _) => "fptoui",
Instr::FPToSI(_, _) => "fptosi",
Instr::UIToFP(_, _) => "uitofp",
Instr::SIToFP(_, _) => "sitofp",
Instr::PtrToInt(_, _) => "ptrtoint",
Instr::IntToPtr(_, _) => "inttoptr",
Instr::BitCast(_, _) => "bitcast",
Instr::Or(..) => "or",
Instr::XOr(..) => "xor",
Instr::ShiftRightLogical(..) => "lshr",
Instr::ShiftRightArithmetic(..) => "ashr",
Instr::ShiftLeft(..) => "shl",
}
}
}
impl<'builder> Block<'builder> {
pub fn build_named<T: Into<String>>(&mut self, name: T, instruction: Instr) -> CompileResult<InstructionValue> {
unsafe {
self.builder.add_instruction(
&self.value,
InstructionData {
kind: instruction,
location: None,
meta: None,
},
name.into(),
)
}
}
pub fn build(&mut self, instruction: Instr) -> CompileResult<InstructionValue> {
unsafe {
let name = instruction.default_name().to_owned();
self.builder.add_instruction(
&self.value,
InstructionData {
kind: instruction,
location: None,
meta: None,
},
name,
)
}
}
pub fn set_instr_location(&self, instruction: InstructionValue, location: DebugLocationValue) {
unsafe {
self.builder.add_instruction_location(&instruction, location);
}
}
pub fn set_instr_metadata(&self, instruction: InstructionValue, location: DebugMetadataValue) {
unsafe {
self.builder.add_instruction_metadata(&instruction, location);
}
}
pub fn terminate(&mut self, instruction: TerminatorKind) -> CompileResult<()> {
unsafe { self.builder.terminate(&self.value, instruction) }
}
pub fn set_terminator_location(&mut self, location: DebugLocationValue) -> CompileResult<()> {
unsafe { self.builder.set_terminator_location(&self.value, location) }
}
/// Delete block if it is unused. Return true if deleted, false if not.
pub fn delete_if_unused(&mut self) -> CompileResult<bool> {
unsafe {
if !self.builder.is_block_used(self.value()) {
self.builder.delete_block(&self.value)?;
Ok(true)
} else {
Ok(false)
}
}
}
pub fn value(&self) -> BlockValue {
self.value
}
}
#[derive(Clone)]
pub struct InstructionData {
kind: Instr,
location: Option<DebugLocationValue>,
meta: Option<DebugMetadataValue>,
}
#[derive(Clone, Copy, Hash)]
pub enum CmpPredicate {
LT,
LE,
GT,
GE,
EQ,
NE,
}
/// https://llvm.org/docs/LangRef.html#instruction-reference
#[derive(Clone)]
pub enum Instr {
Param(usize),
Constant(ConstValue),
/// Add two integers
Add(InstructionValue, InstructionValue),
/// Add two floats
FAdd(InstructionValue, InstructionValue),
/// Subtract two integers
Sub(InstructionValue, InstructionValue),
/// Subtract two floats
FSub(InstructionValue, InstructionValue),
/// Multiply two integers
Mul(InstructionValue, InstructionValue),
/// Multiply two floats
FMul(InstructionValue, InstructionValue),
/// Divide two unsigned integers
UDiv(InstructionValue, InstructionValue),
/// Divide two signed integers
SDiv(InstructionValue, InstructionValue),
/// Divide two floats
FDiv(InstructionValue, InstructionValue),
/// Get the remainder from two unsigned integers
URem(InstructionValue, InstructionValue),
/// Get the remainder from two signed integers
SRem(InstructionValue, InstructionValue),
/// Get the remainder from two floats
FRem(InstructionValue, InstructionValue),
And(InstructionValue, InstructionValue),
Or(InstructionValue, InstructionValue),
XOr(InstructionValue, InstructionValue),
ShiftRightLogical(InstructionValue, InstructionValue),
ShiftRightArithmetic(InstructionValue, InstructionValue),
ShiftLeft(InstructionValue, InstructionValue),
Phi(Vec<InstructionValue>),
Alloca(Type),
Load(InstructionValue, Type),
Store(InstructionValue, InstructionValue),
ArrayAlloca(Type, InstructionValue),
GetElemPtr(InstructionValue, Vec<InstructionValue>),
GetStructElemPtr(InstructionValue, u32),
ExtractValue(InstructionValue, u32),
/// Integer Comparison
ICmp(CmpPredicate, InstructionValue, InstructionValue),
/// FLoat Comparison
FCmp(CmpPredicate, InstructionValue, InstructionValue),
/// The `trunc` instruction truncates the high order bits in value and
/// converts the remaining bits to ty2. Since the source size must be larger
/// than the destination size, `trunc` cannot be a no-op cast. It will
/// always truncate bits.
Trunc(InstructionValue, Type),
/// The `zext` fills the high order bits of the value with zero bits until
/// it reaches the size of the destination type, ty2.
ZExt(InstructionValue, Type),
/// The `sext` instruction performs a sign extension by copying the sign bit
/// (highest order bit) of the value until it reaches the bit size of the
/// type ty2.
SExt(InstructionValue, Type),
/// The `fptrunc` instruction casts a value from a larger floating-point
/// type to a smaller floating-point type.
FPTrunc(InstructionValue, Type),
/// The `fpext` instruction extends the value from a smaller floating-point
/// type to a larger floating-point type.
FPExt(InstructionValue, Type),
/// The `fptoui` instruction takes a value to cast, which must be a scalar
/// or vector floating-point value, and a type to cast it to ty2, which must
/// be an integer type.
FPToUI(InstructionValue, Type),
/// The `fptosi` instruction takes a value to cast, which must be a scalar
/// or vector floating-point value, and a type to cast it to ty2, which must
/// be an integer type.
FPToSI(InstructionValue, Type),
/// The `uitofp` instruction takes a value to cast, which must be a scalar
/// or vector integer value, and a type to cast it to ty2, which must be an
/// floating-point type.
UIToFP(InstructionValue, Type),
/// The `sitofp` instruction takes a value to cast, which must be a scalar
/// or vector integer value, and a type to cast it to ty2, which must be an
/// floating-point type
SIToFP(InstructionValue, Type),
/// The `ptrtoint` instruction converts value to integer type ty2 by
/// interpreting the all pointer representation bits as an integer
/// (equivalent to a bitcast) and either truncating or zero extending that
/// value to the size of the integer type.
PtrToInt(InstructionValue, Type),
/// The `inttoptr` instruction converts value to type ty2 by applying either
/// a zero extension or a truncation depending on the size of the integer
/// value.
IntToPtr(InstructionValue, Type),
/// The `bitcast` instruction converts value to type ty2. It is always a
/// no-op cast because no bits change with this conversion.
BitCast(InstructionValue, Type),
FunctionCall(FunctionValue, Vec<InstructionValue>),
}
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum Type {
I8,
I16,
I32,
I64,
I128,
U8,
U16,
U32,
U64,
U128,
F16,
F32B,
F32,
F64,
F80,
F128,
F128PPC,
Bool,
Void,
CustomType(TypeValue),
Array(Box<Type>, u64),
Ptr(Box<Type>),
}
#[derive(Debug, Clone)]
pub enum ConstValue {
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
Bool(bool),
Str(String),
F16(f32),
F32B(f32),
F32(f32),
F64(f64),
F80(f64),
F128(f64),
F128PPC(f64),
}
#[derive(Clone, Hash)]
pub enum TerminatorKind {
Ret(InstructionValue),
RetVoid,
Br(BlockValue),
CondBr(InstructionValue, BlockValue, BlockValue),
}
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct TypeData {
name: String,
kind: CustomTypeKind,
}
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub enum CustomTypeKind {
NamedStruct(NamedStruct),
}
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct NamedStruct(pub String, pub Vec<Type>);
impl ConstValue {
pub fn get_type(&self) -> Type {
use Type::*;
match self {
ConstValue::I8(_) => I8,
ConstValue::I16(_) => I16,
ConstValue::I32(_) => I32,
ConstValue::I64(_) => I64,
ConstValue::I128(_) => I128,
ConstValue::U8(_) => U8,
ConstValue::U16(_) => U16,
ConstValue::U32(_) => U32,
ConstValue::U64(_) => U64,
ConstValue::U128(_) => U128,
ConstValue::Str(_) => Type::Ptr(Box::new(U8)),
ConstValue::Bool(_) => Bool,
ConstValue::F16(_) => F16,
ConstValue::F32B(_) => F32B,
ConstValue::F32(_) => F32,
ConstValue::F64(_) => F64,
ConstValue::F80(_) => F80,
ConstValue::F128(_) => F128,
ConstValue::F128PPC(_) => F128PPC,
}
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum TypeCategory {
SignedInteger,
UnsignedInteger,
Void,
Real,
Ptr,
CustomType,
Array,
}
impl TypeCategory {
pub fn comparable(&self) -> bool {
match self {
TypeCategory::SignedInteger => true,
TypeCategory::UnsignedInteger => true,
TypeCategory::Real => true,
_ => false,
}
}
pub fn signed(&self) -> bool {
match self {
TypeCategory::SignedInteger => true,
_ => false,
}
}
pub fn integer(&self) -> bool {
match self {
TypeCategory::SignedInteger => true,
TypeCategory::UnsignedInteger => true,
_ => false,
}
}
}
impl Type {
pub fn category(&self) -> TypeCategory {
match self {
Type::I8 | Type::I16 | Type::I32 | Type::I64 | Type::I128 => TypeCategory::SignedInteger,
Type::U8 | Type::U16 | Type::U32 | Type::U64 | Type::U128 => TypeCategory::UnsignedInteger,
Type::F16 | Type::F32B | Type::F32 | Type::F64 | Type::F80 | Type::F128 | Type::F128PPC => {
TypeCategory::Real
}
Type::Bool => TypeCategory::UnsignedInteger,
Type::Void => TypeCategory::Void,
Type::CustomType(_) => TypeCategory::CustomType,
Type::Array(_, _) => TypeCategory::Array,
Type::Ptr(_) => TypeCategory::Ptr,
}
}
pub fn cast_instruction(&self, value: InstructionValue, other: &Type) -> Option<Instr> {
use Type::*;
match (self, other) {
(I8, I16 | I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())),
(I16, I32 | I64 | I128) => Some(Instr::SExt(value, other.clone())),
(I32, I64 | I128) => Some(Instr::SExt(value, other.clone())),
(I64, I128) => Some(Instr::SExt(value, other.clone())),
(I128 | U128, I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
(I64 | U64, I32 | U32 | I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
(I32 | U32, I16 | U16 | I8 | U8) => Some(Instr::Trunc(value, other.clone())),
(I16 | U16, I8 | U8) => Some(Instr::Trunc(value, other.clone())),
(U8 | I8, U8 | I8 | U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => {
Some(Instr::ZExt(value, other.clone()))
}
(U16 | I16, U16 | I16 | U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
(U32 | I32, U32 | I32 | U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
(U64 | I64, U64 | I64 | U128 | I128) => Some(Instr::ZExt(value, other.clone())),
(U128 | I128, U128 | I128) => Some(Instr::ZExt(value, other.clone())),
(U8 | U16 | U32 | U64 | U128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => {
Some(Instr::UIToFP(value, other.clone()))
}
(I8 | I16 | I32 | I64 | I128, F16 | F32 | F32B | F64 | F80 | F128 | F128PPC) => {
Some(Instr::SIToFP(value, other.clone()))
}
(F16 | F32 | F32B | F64 | F80 | F128 | F128PPC, U8 | U16 | U32 | U64 | U128) => {
Some(Instr::FPToUI(value, other.clone()))
}
(F16 | F32 | F32B | F64 | F80 | F128 | F128PPC, I8 | I16 | I32 | I64 | I128) => {
Some(Instr::FPToSI(value, other.clone()))
}
(I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8, Ptr(_)) => {
Some(Instr::IntToPtr(value, other.clone()))
}
(Ptr(_), I128 | U128 | I64 | U64 | I32 | U32 | I16 | U16 | I8 | U8) => {
Some(Instr::PtrToInt(value, other.clone()))
}
(F16, F32 | F32B | F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
(F32 | F32B, F64 | F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
(F64, F80 | F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
(F80, F128 | F128PPC) => Some(Instr::FPExt(value, other.clone())),
(F128PPC | F128, F80 | F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
(F80, F64 | F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
(F64, F32B | F32 | F16) => Some(Instr::FPTrunc(value, other.clone())),
(F32B | F32, F16) => Some(Instr::FPTrunc(value, other.clone())),
_ => None,
}
}
}
impl TerminatorKind {
pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult<Type> {
use TerminatorKind::*;
match self {
Ret(instr_val) => instr_val.get_type(builder),
RetVoid => Ok(Type::Void),
Br(_) => Ok(Type::Void),
CondBr(_, _, _) => Ok(Type::Void),
}
}
}

View File

@ -0,0 +1,69 @@
//! Copied from
//! https://github.com/rust-lang/rust/blob/6b3ae3f6e45a33c2d95fa0362c9b2593e567fd34/library/core/src/fmt/builders.rs#L102
// Copyright (c) The Rust Project Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
use std::fmt;
pub struct PadAdapter<'buf, 'state> {
buf: &'buf mut (dyn fmt::Write + 'buf),
state: &'state mut PadAdapterState,
}
pub struct PadAdapterState {
on_newline: bool,
}
impl Default for PadAdapterState {
fn default() -> Self {
PadAdapterState { on_newline: true }
}
}
impl<'buf, 'state> PadAdapter<'buf, 'state> {
pub fn wrap<'slot, 'fmt: 'buf + 'slot>(
fmt: &'buf mut (dyn fmt::Write + 'buf),
state: &'state mut PadAdapterState,
) -> Self {
PadAdapter { buf: fmt, state }
}
}
impl fmt::Write for PadAdapter<'_, '_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for s in s.split_inclusive('\n') {
if self.state.on_newline {
self.buf.write_str(" ")?;
}
self.state.on_newline = s.ends_with('\n');
self.buf.write_str(s)?;
}
Ok(())
}
fn write_char(&mut self, c: char) -> fmt::Result {
if self.state.on_newline {
self.buf.write_str(" ")?;
}
self.state.on_newline = c == '\n';
self.buf.write_char(c)
}
}

132
reid-llvm-lib/src/util.rs Normal file
View File

@ -0,0 +1,132 @@
use std::{
ffi::{CStr, CString, c_char},
ptr::null_mut,
string::FromUtf8Error,
};
use llvm_sys::{
core::{
LLVMCreateMemoryBufferWithMemoryRange, LLVMDisposeMemoryBuffer, LLVMGetBufferSize,
LLVMGetBufferStart,
},
error::LLVMDisposeErrorMessage,
prelude::LLVMMemoryBufferRef,
};
use crate::{
CompileResult, ErrorKind, Type,
builder::{Builder, InstructionValue},
};
pub fn into_cstring<T: Into<String>>(value: T) -> CString {
let string = value.into();
unsafe { CString::from_vec_with_nul_unchecked((string + "\0").into_bytes()) }
}
pub fn from_cstring(pointer: *mut c_char) -> Option<String> {
if pointer.is_null() {
None
} else {
unsafe { CStr::from_ptr(pointer).to_str().ok().map(|s| s.to_owned()) }
}
}
fn cstring_to_err(value: *mut c_char) -> Result<(), String> {
from_cstring(value)
.filter(|s| !s.is_empty())
.map_or(Ok(()), |s| Err(s))
}
/// Utility struct for LLVM's Error Messages, which need to be disposed
/// manually.
pub struct ErrorMessageHolder(*mut c_char);
impl ErrorMessageHolder {
pub fn null() -> Self {
ErrorMessageHolder(null_mut())
}
pub fn borrow_mut(&mut self) -> *mut *mut c_char {
&mut self.0
}
pub fn into_result(&self) -> Result<(), String> {
cstring_to_err(self.0)
}
}
impl Drop for ErrorMessageHolder {
fn drop(&mut self) {
unsafe {
if !self.0.is_null() {
LLVMDisposeErrorMessage(self.0);
}
}
}
}
/// Utility for creating and handling LLVM MemoryBuffers, needed for printing
/// out ASM and .o -files without relying on LLVM's own API.
pub struct MemoryBufferHolder {
pub buffer: LLVMMemoryBufferRef,
}
impl MemoryBufferHolder {
pub fn empty(name: &str) -> MemoryBufferHolder {
let array = [0i8; 0];
unsafe {
let buffer = LLVMCreateMemoryBufferWithMemoryRange(
array.as_ptr(),
array.len(),
into_cstring(name).as_ptr(),
0,
);
MemoryBufferHolder { buffer }
}
}
pub fn as_buffer(&self) -> Vec<u8> {
unsafe {
let start = LLVMGetBufferStart(self.buffer);
let size = LLVMGetBufferSize(self.buffer);
let mut buff = Vec::with_capacity(size);
for i in 0..size {
buff.push(*start.add(i) as u8);
}
buff
}
}
pub fn as_string(&self) -> Result<String, FromUtf8Error> {
String::from_utf8(self.as_buffer())
}
}
impl Drop for MemoryBufferHolder {
fn drop(&mut self) {
unsafe {
LLVMDisposeMemoryBuffer(self.buffer);
}
}
}
/// Make sure types for given instructions match. Return Ok(type) if they do,
/// and error otherwise.
pub fn match_types(
lhs: &InstructionValue,
rhs: &InstructionValue,
builder: &Builder,
) -> CompileResult<Type> {
let lhs_type = lhs.get_type(&builder);
let rhs_type = rhs.get_type(&builder);
if let (Ok(lhs_t), Ok(rhs_t)) = (lhs_type, rhs_type) {
if lhs_t == rhs_t {
Ok(lhs_t)
} else {
Err(ErrorKind::Null)
}
} else {
Err(ErrorKind::Null)
}
}

7
reid-lsp/.gitignore vendored
View File

@ -1,7 +0,0 @@
.vscode
node_modules
dist
package-lock.json
pnpm-lock.yaml
tsconfig.tsbuildinfo
*.vsix

View File

@ -1 +0,0 @@
enable-pre-post-scripts = true

View File

@ -1,5 +0,0 @@
import { defineConfig } from '@vscode/test-cli';
export default defineConfig({
files: 'out/test/**/*.test.js',
});

View File

@ -1,15 +0,0 @@
.vscode/**
.vscode-test/**
out/**
node_modules/**
src/**
client/**
.gitignore
.yarnrc
webpack.config.js
vsc-extension-quickstart.md
**/tsconfig.json
**/eslint.config.mjs
**/*.map
**/*.ts
**/.vscode-test.*

View File

@ -1,9 +0,0 @@
# Change Log
All notable changes to the "reid-language-server" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release

View File

@ -1,13 +0,0 @@
[package]
name = "reid-language-server"
version = "1.0.0"
edition = "2024"
[dependencies]
socket = "0.0.7"
tokio = { version = "1.47.0", features = ["full"] }
tower-lsp = "0.20.0"
reid = { path = "../reid", version = "1.0.0", registry="gitea-teascade", features=[] }
dashmap = "6.1.0"
serde = "*"
serde_json = "*"

View File

@ -1 +0,0 @@
# Reid Language Server

View File

@ -1,27 +0,0 @@
{
"name": "reid-lsp",
"displayName": "Reid Language Server",
"description": "Language Server Extension for Reid",
"version": "0.0.1",
"engines": {
"vscode": "^1.102.0"
},
"main": "../out/extension.js",
"devDependencies": {
"@types/mocha": "^10.0.10",
"@types/node": "20.x",
"@types/vscode": "^1.102.0",
"@typescript-eslint/eslint-plugin": "^8.31.1",
"@typescript-eslint/parser": "^8.31.1",
"@vscode/test-cli": "^0.0.11",
"@vscode/test-electron": "^2.5.2",
"eslint": "^9.25.1",
"ts-loader": "^9.5.2",
"typescript": "^5.8.3",
"webpack": "^5.99.7",
"webpack-cli": "^6.0.1"
},
"dependencies": {
"vscode-languageclient": "^9.0.1"
}
}

View File

@ -1,96 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as path from 'path';
import { workspace, ExtensionContext, window, languages, SemanticTokensBuilder } from 'vscode';
import {
Executable,
LanguageClient,
LanguageClientOptions,
ServerOptions,
TransportKind
} from 'vscode-languageclient/node';
let client: LanguageClient;
export function activate(context: ExtensionContext) {
const configuration = workspace.getConfiguration('reid-language-server');
let server_path: string = process.env.SERVER_PATH ?? configuration.get("language-server-path") ?? 'reid-language-server';
const regex = /\$(\w+)/;
while (regex.test(server_path)) {
let envVar = regex.exec(server_path)?.[1];
const envVal = envVar ? process.env[envVar] : undefined;
if (envVar === undefined || envVal === undefined) {
console.error(`No such environment variables as ${envVar}`);
}
server_path = server_path.replaceAll(`$${envVar}`, envVal ?? '');
}
const run: Executable = {
command: server_path,
options: {
env: {
...process.env,
RUST_LOG: "debug",
RUST_BACKTRACE: 1,
}
}
};
const serverOptions: ServerOptions = {
run,
debug: run,
};
// Options to control the language client
const clientOptions: LanguageClientOptions = {
// Register the server for plain text documents
documentSelector: [{ scheme: 'file', language: 'reid' }],
synchronize: {
// Notify the server about file changes to '.clientrc files contained in the workspace
fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
},
};
// Create the language client and start the client.
client = new LanguageClient(
'reid-language-server',
'Reid Language Server',
serverOptions,
clientOptions
);
client.info(JSON.stringify(server_path));
client.info(`Loaded Reid Language Server from ${server_path}`);
workspace.onDidOpenTextDocument((e) => { });
client.info("Registering semantic tokens provide");
context.subscriptions.push(languages.registerDocumentSemanticTokensProvider({
language: 'reid',
scheme: 'file'
}, {
provideDocumentSemanticTokens: () => {
const builder = new SemanticTokensBuilder();
return builder.build();
}
}, {
tokenTypes: [],
tokenModifiers: [],
}));
// Start the client. This will also launch the server
client.start();
}
export function deactivate(): Thenable<void> | undefined {
if (!client) {
return undefined;
}
return client.stop();
}

View File

@ -1,15 +0,0 @@
import * as assert from 'assert';
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../../extension';
suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');
test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});

View File

@ -1,24 +0,0 @@
{
"compilerOptions": {
"module": "Node16",
"target": "ES2022",
"lib": [
"ES2022"
],
"sourceMap": true,
"rootDir": "src",
"outDir": "../dist",
"strict": true /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
},
"include": [
"src"
],
"exclude": [
"node_modules",
".vscode-test"
]
}

View File

@ -1,28 +0,0 @@
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
export default [{
files: ["**/*.ts"],
}, {
plugins: {
"@typescript-eslint": typescriptEslint,
},
languageOptions: {
parser: tsParser,
ecmaVersion: 2022,
sourceType: "module",
},
rules: {
"@typescript-eslint/naming-convention": ["warn", {
selector: "import",
format: ["camelCase", "PascalCase"],
}],
curly: "warn",
eqeqeq: "warn",
"no-throw-literal": "warn",
semi: "warn",
},
}];

View File

@ -1,92 +0,0 @@
{
"comments": {
"lineComment": "//",
},
"brackets": [
[
"{",
"}"
],
[
"[",
"]"
],
[
"(",
")"
]
],
"autoClosingPairs": [
{
"open": "{",
"close": "}"
},
{
"open": "[",
"close": "]"
},
{
"open": "(",
"close": ")"
},
{
"open": "'",
"close": "'",
"notIn": [
"string",
"comment"
]
},
{
"open": "\"",
"close": "\"",
"notIn": [
"string"
]
},
],
"autoCloseBefore": ";:.,=}])>` \n\t",
"surroundingPairs": [
[
"{",
"}"
],
[
"[",
"]"
],
[
"(",
")"
],
[
"\"",
"\""
],
],
"folding": {
"markers": {
"start": "^\\s*//\\s*#?region\\b",
"end": "^\\s*//\\s*#?endregion\\b"
}
},
"wordPattern": "[a-Z](\\w*)",
"indentationRules": {
"increaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$",
"decreaseIndentPattern": "^((?!.*?\\/\\*).*\\*/)?\\s*[\\)\\}\\]].*$"
},
"colorizedBracketPairs": [
[
"(",
")"
],
[
"[",
"]"
],
[
"{",
"}"
]
]
}

View File

@ -1,94 +0,0 @@
{
"name": "reid-language-server",
"displayName": "Reid Language Server",
"description": "Language Server Extension for Reid",
"version": "1.0.0",
"repository": {
"url": "https://git.teascade.net/teascade"
},
"engines": {
"vscode": "^1.102.0"
},
"categories": [
"Other"
],
"main": "./dist/extension.js",
"icon": "./reid.png",
"publisher": "Teascade",
"author": {
"email": "teascade@teascade.net",
"name": "Teascade",
"url": "https://teascade.net"
},
"contributes": {
"languages": [
{
"id": "reid",
"extensions": [
".reid"
],
"aliases": [
"Reid"
],
"configuration": "./language-configuration.json",
"icon": {
"dark": "./reid.png",
"light": "./reid.png"
}
}
],
"breakpoints": [
{
"language": "reid"
}
],
"configuration": {
"type": "object",
"title": "reid-language-server",
"properties": {
"reid-language-server.language-server-path": {
"type": "string",
"scope": "window",
"default": "$HOME/.cargo/bin/reid-language-server",
"description": "Path to the Reid Language Server executable"
}
}
},
"grammars": [
{
"language": "reid",
"scopeName": "source.reid",
"path": "./syntaxes/grammar.json"
}
]
},
"scripts": {
"vscode:prepublish": "pnpm run package",
"compile": "npx js-yaml syntaxes/grammar.yaml > syntaxes/grammar.json && webpack",
"watch": "webpack --watch",
"package": "webpack --mode production --devtool hidden-source-map",
"compile-tests": "tsc -p . --outDir out",
"watch-tests": "tsc -p . -w --outDir out",
"pretest": "pnpm run compile-tests && pnpm run compile && pnpm run lint",
"lint": "eslint src",
"test": "vscode-test"
},
"devDependencies": {
"@types/mocha": "^10.0.10",
"@types/node": "20.x",
"@types/vscode": "^1.102.0",
"@typescript-eslint/eslint-plugin": "^8.31.1",
"@typescript-eslint/parser": "^8.31.1",
"@vscode/test-cli": "^0.0.11",
"@vscode/test-electron": "^2.5.2",
"eslint": "^9.25.1",
"js-yaml": "^4.1.0",
"ts-loader": "^9.5.2",
"typescript": "^5.8.3",
"webpack": "^5.99.7",
"webpack-cli": "^6.0.1"
},
"dependencies": {
"vscode-languageclient": "^9.0.1"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,605 +0,0 @@
use std::collections::HashMap;
use std::path::PathBuf;
use dashmap::DashMap;
use reid::ast::lexer::{FullToken, Position};
use reid::error_raporting::{self, ErrorModules, ReidError};
use reid::mir::SourceModuleId;
use reid::parse_module;
use serde::{Deserialize, Serialize};
use tokio::sync::Mutex;
use tower_lsp::lsp_types::{
self, CompletionItem, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic, DiagnosticSeverity,
DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentFilter,
GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverContents, HoverParams, HoverProviderCapability,
InitializeParams, InitializeResult, InitializedParams, Location, MarkedString, MarkupContent, MarkupKind,
MessageType, OneOf, Range, ReferenceParams, RenameParams, SemanticToken, SemanticTokensLegend,
SemanticTokensOptions, SemanticTokensParams, SemanticTokensResult, SemanticTokensServerCapabilities,
ServerCapabilities, TextDocumentItem, TextDocumentRegistrationOptions, TextDocumentSyncCapability,
TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions, TextEdit, Url, WorkspaceEdit,
WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
};
use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc};
use crate::analysis::{MODIFIER_LEGEND, StateMap, StaticAnalysis, TOKEN_LEGEND, analyze};
mod analysis;
#[derive(Debug)]
struct Backend {
client: Client,
analysis: DashMap<PathBuf, StaticAnalysis>,
module_to_path: DashMap<SourceModuleId, PathBuf>,
path_to_module: DashMap<PathBuf, SourceModuleId>,
module_id_counter: Mutex<SourceModuleId>,
}
#[derive(Serialize, Deserialize, Debug)]
struct CompletionData {
token_idx: usize,
path: PathBuf,
}
#[tower_lsp::async_trait]
impl LanguageServer for Backend {
async fn initialize(&self, _: InitializeParams) -> jsonrpc::Result<InitializeResult> {
self.client
.log_message(MessageType::INFO, "Initializing Reid Language Server")
.await;
let sync = TextDocumentSyncOptions {
open_close: Some(true),
change: Some(TextDocumentSyncKind::FULL),
will_save: None,
will_save_wait_until: None,
save: Some(TextDocumentSyncSaveOptions::SaveOptions(lsp_types::SaveOptions {
include_text: Some(true),
})),
};
let capabilities = ServerCapabilities {
hover_provider: Some(HoverProviderCapability::Simple(true)),
completion_provider: Some(CompletionOptions {
trigger_characters: None,
all_commit_characters: None,
completion_item: Some(lsp_types::CompletionOptionsCompletionItem {
label_details_support: Some(true),
}),
resolve_provider: Some(false),
work_done_progress_options: lsp_types::WorkDoneProgressOptions {
work_done_progress: Some(true),
},
}),
text_document_sync: Some(TextDocumentSyncCapability::Options(sync)),
workspace: Some(WorkspaceServerCapabilities {
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
supported: Some(true),
change_notifications: Some(OneOf::Left(true)),
}),
file_operations: None,
}),
semantic_tokens_provider: Some(SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(
lsp_types::SemanticTokensRegistrationOptions {
text_document_registration_options: TextDocumentRegistrationOptions {
document_selector: Some(vec![DocumentFilter {
language: Some("reid".to_owned()),
scheme: Some("file".to_owned()),
pattern: None,
}]),
},
semantic_tokens_options: SemanticTokensOptions {
work_done_progress_options: Default::default(),
legend: SemanticTokensLegend {
token_types: TOKEN_LEGEND.into(),
token_modifiers: MODIFIER_LEGEND.into(),
},
range: None,
full: Some(lsp_types::SemanticTokensFullOptions::Bool(true)),
},
static_registration_options: Default::default(),
},
)),
references_provider: Some(OneOf::Left(true)),
definition_provider: Some(OneOf::Left(true)),
rename_provider: Some(OneOf::Left(true)),
..Default::default()
};
Ok(InitializeResult {
capabilities,
..Default::default()
})
}
async fn initialized(&self, _: InitializedParams) {
self.client
.log_message(MessageType::INFO, "Reid Language Server initialized!")
.await;
}
async fn shutdown(&self) -> jsonrpc::Result<()> {
Ok(())
}
async fn completion(&self, params: CompletionParams) -> jsonrpc::Result<Option<CompletionResponse>> {
let path = PathBuf::from(params.text_document_position.text_document.uri.path());
let analysis = self.analysis.get(&path);
let position = params.text_document_position.position;
let token = if let Some(analysis) = &analysis {
analysis.tokens.iter().enumerate().find(|(_, tok)| {
tok.position.1 == position.line + 1
&& (tok.position.0 <= position.character
&& (tok.position.0 + tok.token.len() as u32) > position.character)
})
} else {
None
};
// dbg!(position, token);
let list = if let Some((idx, _)) = token {
if let Some(token_analysis) = self.analysis.get(&path).unwrap().state.map.get(&idx) {
token_analysis
.autocomplete
.iter()
.map(|autocomplete| {
let mut item =
CompletionItem::new_simple(autocomplete.text.to_string(), autocomplete.kind.to_string());
item.data = Some(
serde_json::to_value(CompletionData {
token_idx: idx,
path: path.clone(),
})
.unwrap(),
);
item.documentation = autocomplete.documentation.as_ref().and_then(|d| {
Some(lsp_types::Documentation::MarkupContent(MarkupContent {
kind: MarkupKind::Markdown,
value: d.clone(),
}))
});
item
})
.collect()
} else {
Vec::new()
}
} else {
Vec::new()
};
// dbg!(&list);
Ok(Some(CompletionResponse::Array(list)))
}
async fn hover(&self, params: HoverParams) -> jsonrpc::Result<Option<Hover>> {
let path = PathBuf::from(params.text_document_position_params.text_document.uri.path());
let analysis = self.analysis.get(&path);
let position = params.text_document_position_params.position;
let token = if let Some(analysis) = &analysis {
analysis.tokens.iter().enumerate().find(|(_, tok)| {
tok.position.1 == position.line + 1
&& (tok.position.0 <= position.character + 1
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
})
} else {
None
};
let (range, ty, documentation) = if let Some((idx, token)) = token {
if let Some(analysis) = self.analysis.get(&path).unwrap().state.map.get(&idx) {
let start = token.position;
let end = token.position.add(token.token.len() as u32);
let range = Range {
start: lsp_types::Position {
line: (start.1 as i32 - 1).max(0) as u32,
character: (start.0 as i32 - 1).max(0) as u32,
},
end: lsp_types::Position {
line: (end.1 as i32 - 1).max(0) as u32,
character: (end.0 as i32 - 1).max(0) as u32,
},
};
if let Some(kind) = &analysis.hover.kind {
match kind {
analysis::HoverKind::Type(type_kind) => (
Some(range),
format!("{}", type_kind),
analysis.hover.documentation.clone(),
),
analysis::HoverKind::Function(name, function_params, return_type) => (
Some(range),
format!(
"{}({}) -> {}",
name,
function_params
.iter()
.map(|p| format!("{}: {}", p.name, p.ty))
.collect::<Vec<_>>()
.join(", "),
return_type
),
analysis.hover.documentation.clone(),
),
}
} else {
(
Some(range),
String::from("No type"),
analysis.hover.documentation.clone(),
)
}
} else {
(None, String::from("no type"), None)
}
} else {
(None, String::from("no token"), None)
};
let contents = if let Some(doc) = documentation {
HoverContents::Array(vec![MarkedString::String(doc), MarkedString::String(format!("`{ty}`"))])
} else {
HoverContents::Markup(MarkupContent {
kind: MarkupKind::Markdown,
value: format!("`{ty}`"),
})
};
Ok(Some(Hover { contents, range }))
}
async fn did_open(&self, params: DidOpenTextDocumentParams) {
self.recompile(TextDocumentItem {
uri: params.text_document.uri,
language_id: params.text_document.language_id,
version: params.text_document.version,
text: params.text_document.text,
})
.await
}
async fn did_change(&self, params: DidChangeTextDocumentParams) {
self.recompile(TextDocumentItem {
text: params.content_changes[0].text.clone(),
uri: params.text_document.uri,
version: params.text_document.version,
language_id: String::new(),
})
.await
}
async fn did_save(&self, params: DidSaveTextDocumentParams) {
self.recompile(TextDocumentItem {
text: params.text.unwrap(),
uri: params.text_document.uri,
version: 0,
language_id: String::new(),
})
.await
}
async fn semantic_tokens_full(
&self,
params: SemanticTokensParams,
) -> jsonrpc::Result<Option<SemanticTokensResult>> {
let path = PathBuf::from(params.text_document.uri.path());
let analysis = self.analysis.get(&path);
let mut semantic_tokens = Vec::new();
if let Some(analysis) = analysis {
let mut prev_line = 0;
let mut prev_start = 0;
for (i, token) in analysis.tokens.iter().enumerate() {
let vscode_line = token.position.1.max(1) - 1;
let vscode_col = token.position.0.max(1) - 1;
let delta_line = vscode_line - prev_line;
let delta_start = if delta_line == 0 {
vscode_col - prev_start
} else {
vscode_col
};
if let Some(token_analysis) = analysis.state.map.get(&i) {
if let Some(symbol_id) = token_analysis.symbol {
let symbol = analysis.state.get_local_symbol(symbol_id);
if let Some(idx) = symbol.kind.into_token_idx(&self.state_map()) {
let semantic_token = SemanticToken {
delta_line,
delta_start,
length: token.token.len() as u32,
token_type: idx,
token_modifiers_bitset: symbol.kind.get_modifier().unwrap_or(0),
};
semantic_tokens.push(semantic_token);
prev_line = vscode_line;
prev_start = vscode_col;
}
}
}
}
}
Ok(Some(SemanticTokensResult::Tokens(lsp_types::SemanticTokens {
result_id: None,
data: semantic_tokens,
})))
}
async fn goto_definition(&self, params: GotoDefinitionParams) -> jsonrpc::Result<Option<GotoDefinitionResponse>> {
let path = PathBuf::from(params.text_document_position_params.text_document.uri.path());
let analysis = self.analysis.get(&path);
let position = params.text_document_position_params.position;
if let Some(analysis) = &analysis {
let token = analysis.tokens.iter().enumerate().find(|(_, tok)| {
tok.position.1 == position.line + 1
&& (tok.position.0 <= position.character + 1
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
});
if let Some(token) = token {
if let Some((module_id, def_token)) = analysis.find_definition(token.0, &self.state_map()) {
return if let Some(path) = self.module_to_path.get(&module_id) {
Ok(Some(GotoDefinitionResponse::Scalar(lsp_types::Location {
uri: Url::from_file_path(path.value()).unwrap(),
range: token_to_range(def_token),
})))
} else {
Ok(None)
};
}
}
};
Ok(None)
}
async fn references(&self, params: ReferenceParams) -> jsonrpc::Result<Option<Vec<Location>>> {
let path = PathBuf::from(params.text_document_position.text_document.uri.path());
let analysis = self.analysis.get(&path);
let position = params.text_document_position.position;
if let Some(analysis) = &analysis {
let token = analysis.tokens.iter().enumerate().find(|(_, tok)| {
tok.position.1 == position.line + 1
&& (tok.position.0 <= position.character + 1
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
});
if let Some(token) = token {
let reference_tokens = analysis.find_references(token.0, &self.state_map());
let mut locations = Vec::new();
if let Some(reference_tokens) = reference_tokens {
for (module_id, symbol_idx) in reference_tokens {
if let Some(path) = self.module_to_path.get(&module_id) {
let url = Url::from_file_path(path.value()).unwrap();
if let Some(inner_analysis) = self.analysis.get(path.value()) {
if let Some(token_idx) = inner_analysis.state.symbol_to_token.get(&symbol_idx) {
let token = inner_analysis.tokens.get(*token_idx).unwrap();
locations.push(lsp_types::Location {
uri: url,
range: token_to_range(token),
});
}
}
}
}
}
Ok(Some(locations))
} else {
Ok(None)
}
} else {
Ok(None)
}
}
async fn rename(&self, params: RenameParams) -> jsonrpc::Result<Option<WorkspaceEdit>> {
let path = PathBuf::from(params.text_document_position.text_document.uri.path());
let analysis = self.analysis.get(&path);
let position = params.text_document_position.position;
if let Some(analysis) = &analysis {
let token = analysis.tokens.iter().enumerate().find(|(_, tok)| {
tok.position.1 == position.line + 1
&& (tok.position.0 <= position.character + 1
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
});
if let Some(token) = token {
let symbols = analysis.find_references(token.0, &self.state_map());
let mut changes: HashMap<Url, Vec<TextEdit>> = HashMap::new();
if let Some(symbols) = symbols {
for (module_id, symbol_id) in symbols {
let path = self.module_to_path.get(&module_id);
if let Some(path) = path {
let url = Url::from_file_path(path.value()).unwrap();
let analysis = self.analysis.get(&path.clone());
if let Some(analysis) = analysis {
if let Some(token_idx) = analysis.state.symbol_to_token.get(&symbol_id) {
let token = analysis.tokens.get(*token_idx).unwrap();
// edits = changes.get(k)
let edit = TextEdit {
range: token_to_range(token),
new_text: params.new_name.clone(),
};
if let Some(edits) = changes.get_mut(&url) {
edits.push(edit);
} else {
changes.insert(url, vec![edit]);
}
}
}
}
}
}
Ok(Some(WorkspaceEdit {
changes: Some(changes),
document_changes: None,
change_annotations: None,
}))
} else {
Ok(None)
}
} else {
Ok(None)
}
}
}
fn token_to_range(token: &FullToken) -> lsp_types::Range {
Range {
start: lsp_types::Position {
line: token.position.1.max(1) - 1,
character: token.position.0.max(1) - 1,
},
end: lsp_types::Position {
line: token.position.1.max(1) - 1,
character: token.position.0.max(1) - 1 + token.token.len() as u32,
},
}
}
impl Backend {
fn state_map(&self) -> StateMap {
let mut state_map = HashMap::new();
for path_state in self.analysis.iter() {
let (path, state) = path_state.pair();
if let Some(module_id) = self.path_to_module.get(path) {
state_map.insert(*module_id, state.state.clone());
}
}
state_map
}
async fn recompile(&self, params: TextDocumentItem) {
let file_path = PathBuf::from(params.uri.clone().path());
let mut map: ErrorModules = Default::default();
for url_module in self.path_to_module.iter() {
let (url, module) = url_module.pair();
map.add_module(
url.file_name().unwrap().to_str().unwrap().to_owned(),
Some(url.clone()),
Some(*module),
);
}
let module_id = if let Some(module_id) = self.path_to_module.get(&file_path) {
*module_id
} else {
let mut lock = self.module_id_counter.lock().await;
let module_id = lock.increment();
drop(lock);
self.path_to_module.insert(file_path.clone(), module_id);
self.module_to_path.insert(module_id, file_path.clone());
module_id
};
let parse_res = parse(&params.text, file_path.clone(), &mut map, module_id);
let (tokens, result) = match parse_res {
Ok((module_id, tokens)) => (
tokens.clone(),
analyze(module_id, tokens, file_path.clone(), &mut map, &self.state_map()),
),
Err(e) => (Vec::new(), Err(e)),
};
let mut diagnostics = Vec::new();
match result {
Ok(Some(mut analysis)) => {
if let Some(reid_error) = &mut analysis.error {
self.client
.log_message(
MessageType::INFO,
format!("Successfully compiled despite parsing errors!"),
)
.await;
reid_error.errors.dedup();
for error in &reid_error.errors {
diagnostics.push(reid_error_into_diagnostic(error, &tokens));
self.client.log_message(MessageType::INFO, format!("{}", error)).await;
}
}
self.analysis.insert(file_path, analysis);
}
Ok(_) => {}
Err(mut reid_error) => {
reid_error.errors.dedup();
for error in &reid_error.errors {
diagnostics.push(reid_error_into_diagnostic(error, &tokens));
self.client.log_message(MessageType::INFO, format!("{}", error)).await;
}
}
}
self.client
.publish_diagnostics(params.uri.clone(), diagnostics, Some(params.version))
.await;
}
}
fn reid_error_into_diagnostic(error: &error_raporting::ErrorKind, tokens: &Vec<FullToken>) -> Diagnostic {
let meta = error.get_meta();
let positions = meta
.range
.into_position(&tokens)
.unwrap_or((Position(0, 0), Position(0, 0)));
Diagnostic {
range: Range {
start: lsp_types::Position {
line: ((positions.0.1 as i32) - 1).max(0) as u32,
character: ((positions.0.0 as i32) - 1).max(0) as u32,
},
end: lsp_types::Position {
line: ((positions.1.1 as i32) - 1).max(0) as u32,
character: ((positions.1.0 as i32) - 1).max(0) as u32,
},
},
severity: Some(DiagnosticSeverity::ERROR),
code: None,
code_description: None,
source: Some(error.get_type_str().to_owned()),
message: format!("{}", error),
related_information: None,
tags: None,
data: None,
}
}
fn parse(
source: &str,
path: PathBuf,
map: &mut ErrorModules,
module_id: SourceModuleId,
) -> Result<(SourceModuleId, Vec<FullToken>), ReidError> {
let file_name = path.file_name().unwrap().to_str().unwrap().to_owned();
Ok(parse_module(
source,
file_name.clone(),
Some(path),
map,
Some(module_id),
)?)
}
#[tokio::main]
async fn main() {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, socket) = LspService::new(|client| Backend {
client,
analysis: DashMap::new(),
module_to_path: DashMap::new(),
path_to_module: DashMap::new(),
module_id_counter: Mutex::new(SourceModuleId(0)),
});
Server::new(stdin, stdout, socket).serve(service).await;
}

View File

@ -1,281 +0,0 @@
{
"scopeName": "source.reid",
"patterns": [
{
"include": "#expression"
}
],
"repository": {
"expression": {
"patterns": [
{
"include": "#comment"
},
{
"include": "#fn-signature"
},
{
"include": "#namespace"
},
{
"include": "#common-type"
},
{
"include": "#struct-definition"
},
{
"include": "#binop"
},
{
"include": "#cast"
},
{
"include": "#function-call"
},
{
"include": "#parenthesis"
},
{
"include": "#array"
},
{
"include": "#keywords"
},
{
"include": "#number-literal"
},
{
"include": "#string-literal"
},
{
"include": "#identifier"
},
{
"include": "#punctuation"
}
]
},
"punctuation": {
"patterns": [
{
"match": "::",
"name": "keyword.operator.namespace.reid"
},
{
"match": ":",
"name": "keyword.operator.colon.reid"
},
{
"match": ";",
"name": "punctuation.semi.reid"
},
{
"match": ".",
"name": "punctuation.dot.reid"
},
{
"match": ",",
"name": "punctuation.comma.reid"
},
{
"match": "\\{|\\}",
"name": "punctuation.brackets.curly.reid"
},
{
"match": "\\(|\\)",
"name": "punctuation.parenthesis.reid"
}
]
},
"comment": {
"match": "\\/\\/(.|\\/)*",
"name": "comment.line.double-slash.reid"
},
"struct-definition": {
"match": "(struct)\\s*(\\w+)",
"captures": {
"1": {
"name": "keyword.struct.reid"
},
"2": {
"name": "entity.name.type"
}
}
},
"struct-expression": {
"begin": "\\b([A-Z]\\w*)\\s*\\{",
"end": "\\}",
"captures": {
"1": {
"name": "entity.name.type.struct.reid"
}
},
"patterns": [
{
"include": "#expression"
}
]
},
"number-literal": {
"patterns": [
{
"match": "\\b0x[0-9a-fA-F]+(\\.[0-9a-fA-F]+)?\\b",
"name": "constant.hexadecimal"
},
{
"match": "\\b0o[0-7]+(\\.[0-7]+)?\\b",
"name": "constant.octal"
},
{
"match": "\\b0b[01]+(\\.[01]+)?\\b",
"name": "constant.binary"
},
{
"match": "\\b[0-9]+(\\.[0-9]+)?\\b",
"name": "constant.numeric"
}
]
},
"string-literal": {
"begin": "\"",
"end": "\"",
"name": "string.quoted.double",
"patterns": [
{
"match": "\\\\\\w",
"name": "constant.character.escape"
}
]
},
"namespace": {
"match": "(\\w+)(\\:\\:)",
"captures": {
"1": {
"name": "entity.name.namespace.reid"
},
"2": {
"name": "keyword.operator.namespace.reid"
}
}
},
"cast": {
"match": "(as)\\s+(\\w+)",
"captures": {
"1": {
"name": "keyword.cast.reid"
},
"2": {
"name": "entity.name.type.reid"
}
}
},
"function-call": {
"begin": "(\\w+)?(\\()",
"end": "(\\))",
"beginCaptures": {
"1": {
"name": "entity.name.function.reid"
},
"2": {
"name": "punctuation.parenthesis.reid"
}
},
"endCaptures": {
"1": {
"name": "punctuation.parenthesis.reid"
}
},
"patterns": [
{
"include": "#expression"
}
]
},
"parenthesis": {
"begin": "\\(",
"end": "\\)",
"beginCaptures": {
"0": {
"name": "keyword.operator.parenthesis.reid"
}
},
"endCaptures": {
"0": {
"name": "keyword.operator.parenthesis.reid"
}
},
"patterns": [
{
"include": "#expression"
}
]
},
"identifier": {
"patterns": [
{
"match": "\\b(?:\\w+)\\b",
"name": "variable.language.reid"
}
]
},
"keywords": {
"patterns": [
{
"match": "\\b(?:let|mut|pub|extern)\\b",
"name": "storage.type.reid"
},
{
"match": "\\bimport\\b",
"name": "keyword.import.reid"
},
{
"match": "\\bbinop\\b",
"name": "keyword.binop.reid"
},
{
"match": "\\bimpl\\b",
"name": "keyword.impl.reid"
},
{
"match": "\\b(?:if|return|for|in)\\b",
"name": "keyword.control"
},
{
"match": "\\bself\\b",
"name": "variable.language.self.reid"
},
{
"match": "\\bfn\\b",
"name": "keyword.fn.reid"
}
]
},
"binop": {
"match": "\\<\\=|\\>\\=|\\=\\=|\\<|\\>|\\*|\\+|\\-|\\^|\\&\\&|\\&",
"name": "keyword.operator.math.reid"
},
"array": {
"begin": "\\[",
"end": "\\]",
"beginCaptures": {
"0": {
"name": "entity.name.type.array.reid"
}
},
"endCaptures": {
"0": {
"name": "entity.name.type.array.reid"
}
},
"patterns": [
{
"include": "#expression"
}
]
},
"common-type": {
"match": "\\b(?:u8|u16|u32|u64|u128|i8|i16|i32|i64|i128|f16|f16b|f32|f64|f80|f128|f128ppc|bool|char|([A-Z]\\w*))\\b",
"name": "entity.name.type.common.reid"
}
}
}

View File

@ -1,149 +0,0 @@
scopeName: source.reid
patterns:
- include: "#expression"
repository:
expression:
patterns:
- include: "#comment"
- include: "#fn-signature"
- include: "#namespace"
- include: "#common-type"
- include: "#struct-definition"
- include: "#binop"
- include: "#cast"
- include: "#function-call"
- include: "#parenthesis"
- include: "#array"
- include: "#keywords"
- include: "#number-literal"
- include: "#string-literal"
- include: "#identifier"
- include: "#punctuation"
punctuation:
patterns:
- match: "::"
name: keyword.operator.namespace.reid
- match: ":"
name: keyword.operator.colon.reid
- match: ";"
name: punctuation.semi.reid
- match: "."
name: punctuation.dot.reid
- match: ","
name: punctuation.comma.reid
- match: "\\{|\\}"
name: punctuation.brackets.curly.reid
- match: "\\(|\\)"
name: punctuation.parenthesis.reid
comment:
match: "\\/\\/(.|\\/)*"
name: comment.line.double-slash.reid
struct-definition:
match: "(struct)\\s*(\\w+)"
captures:
1:
name: keyword.struct.reid
2:
name: entity.name.type
struct-expression:
begin: "\\b([A-Z]\\w*)\\s*\\{"
end: "\\}"
captures:
1:
name: entity.name.type.struct.reid
patterns:
- include: "#expression"
number-literal:
patterns:
- match: "\\b0x[0-9a-fA-F]+(\\.[0-9a-fA-F]+)?\\b"
name: "constant.hexadecimal"
- match: "\\b0o[0-7]+(\\.[0-7]+)?\\b"
name: "constant.octal"
- match: "\\b0b[01]+(\\.[01]+)?\\b"
name: "constant.binary"
- match: "\\b[0-9]+(\\.[0-9]+)?\\b"
name: "constant.numeric"
string-literal:
begin: '"'
end: '"'
name: string.quoted.double
patterns:
- match: "\\\\\\w"
name: constant.character.escape
namespace:
match: "(\\w+)(\\:\\:)"
captures:
1:
name: entity.name.namespace.reid
2:
name: keyword.operator.namespace.reid
cast:
match: "(as)\\s+(\\w+)"
captures:
1:
name: keyword.cast.reid
2:
name: entity.name.type.reid
function-call:
begin: "(\\w+)?(\\()"
end: "(\\))"
beginCaptures:
1:
name: entity.name.function.reid
2:
name: punctuation.parenthesis.reid
endCaptures:
1:
name: punctuation.parenthesis.reid
patterns:
- include: "#expression"
parenthesis:
begin: "\\("
end: "\\)"
beginCaptures:
0:
name: keyword.operator.parenthesis.reid
endCaptures:
0:
name: keyword.operator.parenthesis.reid
patterns:
- include: "#expression"
identifier:
patterns:
- match: "\\b(?:\\w+)\\b"
name: variable.language.reid
keywords:
patterns:
- match: "\\b(?:let|mut|pub|extern)\\b"
name: storage.type.reid
- match: "\\bimport\\b"
name: keyword.import.reid
- match: "\\bbinop\\b"
name: keyword.binop.reid
- match: "\\bimpl\\b"
name: keyword.impl.reid
- match: "\\b(?:if|return|for|in)\\b"
name: keyword.control
- match: "\\bself\\b"
name: variable.language.self.reid
- match: "\\bfn\\b"
name: keyword.fn.reid
binop:
match: "\\<\\=|\\>\\=|\\=\\=|\\<|\\>|\\*|\\+|\\-|\\^|\\&\\&|\\&"
name: keyword.operator.math.reid
array:
begin: "\\["
end: "\\]"
beginCaptures:
0:
name: entity.name.type.array.reid
endCaptures:
0:
name: entity.name.type.array.reid
patterns:
- include: "#expression"
common-type:
match: "\\b(?:u8|u16|u32|u64|u128|i8|i16|i32|i64|i128|f16|f16b|f32|f64|f80|f128|f128ppc|bool|char|([A-Z]\\w*))\\b"
name: entity.name.type.common.reid

View File

@ -1,29 +0,0 @@
{
"compilerOptions": {
"module": "Node16",
"target": "ES2022",
"lib": [
"ES2022"
],
"sourceMap": true,
"rootDir": "src",
"outDir": "out",
"strict": true /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
},
"include": [
"src"
],
"exclude": [
"node_modules",
".vscode-test"
],
"references": [
{
"path": "./client/"
},
]
}

View File

@ -1,48 +0,0 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your extension and command.
* The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesnt yet need to load the plugin.
* `src/extension.ts` - this is the main file where you will provide the implementation of your command.
* The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
* We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
## Setup
* install the recommended extensions (amodio.tsl-problem-matcher, ms-vscode.extension-test-runner, and dbaeumer.vscode-eslint)
## Get up and running straight away
* Press `F5` to open a new window with your extension loaded.
* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
* Set breakpoints in your code inside `src/extension.ts` to debug your extension.
* Find output from your extension in the debug console.
## Make changes
* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Explore the API
* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.
## Run tests
* Install the [Extension Test Runner](https://marketplace.visualstudio.com/items?itemName=ms-vscode.extension-test-runner)
* Run the "watch" task via the **Tasks: Run Task** command. Make sure this is running, or tests might not be discovered.
* Open the Testing view from the activity bar and click the Run Test" button, or use the hotkey `Ctrl/Cmd + ; A`
* See the output of the test result in the Test Results view.
* Make changes to `src/test/extension.test.ts` or create new test files inside the `test` folder.
* The provided test runner will only consider files matching the name pattern `**.test.ts`.
* You can create folders inside the `test` folder to structure your tests any way you want.
## Go further
* Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).
* [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace.
* Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).

View File

@ -1,48 +0,0 @@
//@ts-check
'use strict';
const path = require('path');
//@ts-check
/** @typedef {import('webpack').Configuration} WebpackConfig **/
/** @type WebpackConfig */
const extensionConfig = {
target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
entry: './client/src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
output: {
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
path: path.resolve(__dirname, 'dist'),
filename: 'extension.js',
libraryTarget: 'commonjs2'
},
externals: {
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
// modules added here also need to be added in the .vscodeignore file
},
resolve: {
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader'
}
]
}
]
},
devtool: 'nosources-source-map',
infrastructureLogging: {
level: "log", // enables logging required for problem matchers
},
};
module.exports = [extensionConfig];

View File

@ -1,23 +1,19 @@
[package] [package]
name = "reid" name = "reid"
version = "1.0.0" version = "1.0.0-beta.2"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features] [features]
default = ["color", "cli"] default = ["color"]
color = ["colored"] color = ["colored"]
cli = ["argh", "stderrlog"]
[dependencies] [dependencies]
## Make it easier to generate errors ## Make it easier to generate errors
thiserror = "1.0.44" thiserror = "1.0.44"
reid-lib = { path = "../reid-llvm-lib", version = "1.0.0", registry="gitea-teascade" } reid-lib = { path = "../reid-llvm-lib", version = "1.0.0-beta.1", registry="gitea-teascade" }
argh = { version = "0.1.13", optional = true } colored = {version = "3.0.0", optional = true}
stderrlog = { version = "0.6.0", optional = true }
log = "*"
colored = { version = "3.0.0", optional = true }

View File

@ -12,6 +12,7 @@ fn main() -> Result<(), std::io::Error> {
libraries.push(libname); libraries.push(libname);
} }
dbg!(&filename);
let path = PathBuf::from(filename).canonicalize().unwrap(); let path = PathBuf::from(filename).canonicalize().unwrap();
let parent = path.with_extension(""); let parent = path.with_extension("");
let llvm_ir_path = parent.with_extension("ll"); let llvm_ir_path = parent.with_extension("ll");
@ -30,27 +31,27 @@ fn main() -> Result<(), std::io::Error> {
match compile_simple(&text, PathBuf::from(&path), Some(cpu), vec![features]) { match compile_simple(&text, PathBuf::from(&path), Some(cpu), vec![features]) {
Ok(( Ok((
CompileOutput { CompileOutput {
triple: _triple, triple,
assembly, assembly,
obj_buffer, obj_buffer,
llvm_ir: _llvm_ir, llvm_ir,
}, },
CustomIRs { llir, mir }, CustomIRs { llir, mir },
)) => { )) => {
log::trace!("{}", _llvm_ir); println!("{}", llvm_ir);
log::debug!("Compiled with triple: {}\n", &_triple);
log::debug!("Output LLVM IR to {:?}", llvm_ir_path);
log::debug!("Output Assembly to {:?}", asm_path);
log::debug!("Output Object-file to {:?}\n", object_path);
log::debug!("Output LLIR-file to {:?}\n", llir_path);
log::debug!("Output MIR-file to {:?}\n", mir_path);
fs::write(&llvm_ir_path, &_llvm_ir).expect("Could not write LLVM IR -file!");
fs::write(&asm_path, &assembly).expect("Could not write Assembly-file!");
fs::write(&object_path, &obj_buffer).expect("Could not write Object-file!");
fs::write(&llir_path, &llir).expect("Could not write LLIR-file!");
fs::write(&mir_path, &mir).expect("Could not write MIR-file!");
let after = std::time::SystemTime::now(); let after = std::time::SystemTime::now();
println!("Compiled with triple: {}\n", &triple);
fs::write(&llvm_ir_path, &llvm_ir).expect("Could not write LLVM IR -file!");
println!("Output LLVM IR to {:?}", llvm_ir_path);
fs::write(&asm_path, &assembly).expect("Could not write Assembly-file!");
println!("Output Assembly to {:?}", asm_path);
fs::write(&object_path, &obj_buffer).expect("Could not write Object-file!");
println!("Output Object-file to {:?}\n", object_path);
fs::write(&llir_path, &llir).expect("Could not write LLIR-file!");
println!("Output LLIR-file to {:?}\n", llir_path);
fs::write(&mir_path, &mir).expect("Could not write MIR-file!");
println!("Output MIR-file to {:?}\n", mir_path);
println!( println!(
"Compilation took: {:.2}ms\n", "Compilation took: {:.2}ms\n",
(after.duration_since(before).unwrap().as_micros() as f32) / 1000. (after.duration_since(before).unwrap().as_micros() as f32) / 1000.
@ -59,7 +60,7 @@ fn main() -> Result<(), std::io::Error> {
println!("Linking {:?}", &object_path); println!("Linking {:?}", &object_path);
let linker = std::env::var("LD").unwrap_or("ld".to_owned()); let linker = std::env::var("LD").unwrap_or("ld".to_owned());
let mut linker = LDRunner::from_command(&linker).with_library("c").with_library("m"); let mut linker = LDRunner::from_command(&linker).with_library("c");
for library in libraries { for library in libraries {
linker = linker.with_library(&library); linker = linker.with_library(&library);
} }
@ -68,7 +69,7 @@ fn main() -> Result<(), std::io::Error> {
Err(e) => panic!("{}", e), Err(e) => panic!("{}", e),
}; };
} else { } else {
log::error!("Please input compiled file path!") println!("Please input compiled file path!")
} }
Ok(()) Ok(())
} }

View File

@ -1,9 +1,9 @@
extern fn puts(message: *char) -> i32; extern fn puts(message: *char) -> i32;
extern fn malloc(size: u64) -> *u8;
extern fn free(ptr: *u8); extern fn free(ptr: *u8);
extern fn div(numerator: i32, denominator: i32) -> div_t; extern fn div(numerator: i32, denominator: i32) -> div_t;
/// Editable string value that can be printed and extended
struct String { struct String {
inner: *char, inner: *char,
length: u64, length: u64,
@ -12,18 +12,15 @@ struct String {
} }
impl String { impl String {
/// Returns a new empty `String`-object, which must later be manually freed.
pub fn new() -> String { pub fn new() -> String {
String { String {
inner: char::malloc(0), inner: allocate(0),
length: 0, length: 0,
max_length: 0, max_length: 0,
must_be_freed: true, must_be_freed: true,
} }
} }
/// Creates a new `String`-object containing initially data from the given
/// string-literal which must be later freed.
pub fn from(str: *char) -> String { pub fn from(str: *char) -> String {
let length = str_length(str) as u64; let length = str_length(str) as u64;
let mut new = String::new(); let mut new = String::new();
@ -37,17 +34,15 @@ impl String {
return new; return new;
} }
/// Same as `concat`
pub fn push(&mut self, other: String) { pub fn push(&mut self, other: String) {
for i in 0 .. (str_length(other.inner) - 1) { for i in 0 .. (str_length(other.inner) - 1) {
add_char(self, other.inner[i]); add_char(self, other.inner[i]);
} }
} }
/// Adds a character to the end of this string
pub fn add_char(&mut self, c: char) { pub fn add_char(&mut self, c: char) {
if ((*self).length + 1) >= (*self).max_length { if ((*self).length + 1) >= (*self).max_length {
let new = char::malloc((*self).max_length + 4); let new = allocate((*self).max_length + 4) as *char;
copy_bits((*self).inner, new, (*self).max_length); copy_bits((*self).inner, new, (*self).max_length);
if (*self).must_be_freed == true { if (*self).must_be_freed == true {
@ -63,7 +58,6 @@ impl String {
(*self).length = (*self).length + 1; (*self).length = (*self).length + 1;
} }
/// Formats the given number into the end of the string.
pub fn push_num(&mut self, num: u64) { pub fn push_num(&mut self, num: u64) {
if num >= 10 { if num >= 10 {
self.push_num(num / 10) self.push_num(num / 10)
@ -82,22 +76,18 @@ impl String {
else if rem == 9 { self.add_char('9'); } else if rem == 9 { self.add_char('9'); }
} }
/// Concatenates `source` to the end of `destination`.
pub fn concat(&mut self, other: &String) { pub fn concat(&mut self, other: &String) {
for i in 0 .. *other.length { for i in 0 .. *other.length {
self.add_char(*other.inner[i]); self.add_char(*other.inner[i]);
} }
} }
/// Edits given `string` by setting the character at index `position` to be
/// `c`.
pub fn set(&mut self, c: char, position: u64) { pub fn set(&mut self, c: char, position: u64) {
if position <= (*self).length { if position <= (*self).length {
(*self).inner[position] = c; (*self).inner[position] = c;
} }
} }
/// Frees this given string
pub fn free(&self) { pub fn free(&self) {
free((*self).inner as *u8); free((*self).inner as *u8);
} }
@ -122,28 +112,27 @@ struct div_t {
remainder: i32, remainder: i32,
} }
/// Print given string to stdout
pub fn print(message: String) { pub fn print(message: String) {
puts(message.inner); puts(message.inner);
} }
/// Divide an integer, returning the quotient and remainder.
pub fn int_div(numerator: i32, denominator: i32) -> div_t { pub fn int_div(numerator: i32, denominator: i32) -> div_t {
return div(numerator, denominator); return div(numerator, denominator);
} }
/// (deprecated) creates a new editable string pub fn allocate(size: u64) -> *u8 {
malloc(size)
}
pub fn new_string() -> String { pub fn new_string() -> String {
String { String {
inner: char::malloc(0), inner: allocate(0),
length: 0, length: 0,
max_length: 0, max_length: 0,
must_be_freed: true, must_be_freed: true,
} }
} }
/// Creates a new `String`-object containing initially data from the given
/// string-literal which must be later freed.
pub fn from_str(str: *char) -> String { pub fn from_str(str: *char) -> String {
let length = str_length(str) as u64; let length = str_length(str) as u64;
let mut new = new_string(); let mut new = new_string();
@ -157,10 +146,9 @@ pub fn from_str(str: *char) -> String {
return new; return new;
} }
/// (deprecated) Adds a character to the end of a given string
pub fn add_char(string: &mut String, c: char) { pub fn add_char(string: &mut String, c: char) {
if ((*string).length + 1) >= (*string).max_length { if ((*string).length + 1) >= (*string).max_length {
let new = char::malloc((*string).max_length + 4); let new = allocate((*string).max_length + 4) as *char;
copy_bits((*string).inner, new, (*string).max_length); copy_bits((*string).inner, new, (*string).max_length);
if (*string).must_be_freed == true { if (*string).must_be_freed == true {
@ -176,14 +164,12 @@ pub fn add_char(string: &mut String, c: char) {
(*string).length = (*string).length + 1; (*string).length = (*string).length + 1;
} }
/// (deprecated) sets a character in a string
pub fn set_char(string: &mut String, c: char, position: u64) { pub fn set_char(string: &mut String, c: char, position: u64) {
if position <= (*string).length { if position <= (*string).length {
(*string).inner[position] = c; (*string).inner[position] = c;
} }
} }
/// (deprecated) frees given string
pub fn free_string(string: &String) { pub fn free_string(string: &String) {
free((*string).inner as *u8); free((*string).inner as *u8);
} }
@ -202,7 +188,6 @@ fn str_length(string: *char) -> u32 {
return pos + 1; return pos + 1;
} }
/// (deprecated) concatenates number to the end of this string.
pub fn add_num_to_str(string: &mut String, num: u64) { pub fn add_num_to_str(string: &mut String, num: u64) {
if num >= 10 { if num >= 10 {
add_num_to_str(string, num / 10) add_num_to_str(string, num / 10)
@ -221,15 +206,12 @@ pub fn add_num_to_str(string: &mut String, num: u64) {
else if rem == 9 { add_char(string, '9'); } else if rem == 9 { add_char(string, '9'); }
} }
/// (deprecated) concatenates two strings to the destination
pub fn concat_strings(destination: &mut String, source: String) { pub fn concat_strings(destination: &mut String, source: String) {
for i in 0 .. (str_length(source.inner) - 1) { for i in 0 .. (str_length(source.inner) - 1) {
add_char(destination, source.inner[i]); add_char(destination, source.inner[i]);
} }
} }
/// Returns `value` as clamped between `min` and `max`. Equivalent to
/// `max(min(value, max), min)`
pub fn clamp(min: f32, max: f32, value: f32) -> f32 { pub fn clamp(min: f32, max: f32, value: f32) -> f32 {
if value > max { if value > max {
return max; return max;
@ -240,7 +222,6 @@ pub fn clamp(min: f32, max: f32, value: f32) -> f32 {
return value; return value;
} }
/// Returns the absolute value of `value`.
pub fn abs(f: f32) -> f32 { pub fn abs(f: f32) -> f32 {
if f < 0.0 { if f < 0.0 {
return f * (0.0 - 1.0); return f * (0.0 - 1.0);

View File

@ -7,7 +7,7 @@ static HEXADECIMAL_NUMERICS: &[char] = &[
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
]; ];
#[derive(Eq, PartialEq, Clone, PartialOrd, Ord, Hash)] #[derive(Eq, PartialEq, Clone, PartialOrd, Ord)]
pub enum Token { pub enum Token {
/// Values /// Values
Identifier(String), Identifier(String),
@ -114,9 +114,6 @@ pub enum Token {
Unknown(char), Unknown(char),
Whitespace(String),
Comment(String),
Doc(String),
Eof, Eof,
} }
@ -195,9 +192,6 @@ impl ToString for Token {
Token::Eof => String::new(), Token::Eof => String::new(),
Token::Slash => String::from('/'), Token::Slash => String::from('/'),
Token::Percent => String::from('%'), Token::Percent => String::from('%'),
Token::Whitespace(val) => val.clone(),
Token::Comment(val) => format!("//{}", val.clone()),
Token::Doc(val) => format!("///{}", val.clone()),
Token::Unknown(val) => val.to_string(), Token::Unknown(val) => val.to_string(),
} }
} }
@ -213,7 +207,7 @@ impl std::fmt::Debug for Token {
} }
/// A token with a position /// A token with a position
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FullToken { pub struct FullToken {
pub token: Token, pub token: Token,
pub position: Position, pub position: Position,
@ -299,37 +293,13 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
let variant = match character { let variant = match character {
// Whitespace // Whitespace
w if w.is_whitespace() => { w if w.is_whitespace() => continue,
let mut whitespace = String::from(*w);
while let Some(w) = cursor.first() {
if !w.is_whitespace() {
break;
}
whitespace.push(cursor.next().unwrap());
}
Token::Whitespace(whitespace)
}
// Comments // Comments
'/' if cursor.first() == Some('/') => { '/' if cursor.first() == Some('/') => {
cursor.next();
let doc = if cursor.first() == Some('/') {
cursor.next();
true
} else {
false
};
let mut comment = String::new();
while !matches!(cursor.first(), Some('\n') | None) { while !matches!(cursor.first(), Some('\n') | None) {
if let Some(c) = cursor.next() { cursor.next();
comment.push(c);
}
}
if doc {
Token::Doc(comment)
} else {
Token::Comment(comment)
} }
continue;
} }
'\"' | '\'' => { '\"' | '\'' => {
let mut value = String::new(); let mut value = String::new();

View File

@ -88,7 +88,7 @@ pub enum ExpressionKind {
/// Array-indexed, e.g. <expr>[<expr>] /// Array-indexed, e.g. <expr>[<expr>]
Indexed(Box<Expression>, Box<Expression>), Indexed(Box<Expression>, Box<Expression>),
/// Struct-accessed, e.g. <expr>.<expr> /// Struct-accessed, e.g. <expr>.<expr>
Accessed(Box<Expression>, String, TokenRange), Accessed(Box<Expression>, String),
/// Associated function call, but with a shorthand /// Associated function call, but with a shorthand
AccessCall(Box<Expression>, Box<FunctionCallExpression>), AccessCall(Box<Expression>, Box<FunctionCallExpression>),
Binop(BinaryOperator, Box<Expression>, Box<Expression>), Binop(BinaryOperator, Box<Expression>, Box<Expression>),
@ -159,12 +159,7 @@ impl BinaryOperator {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FunctionCallExpression { pub struct FunctionCallExpression(pub String, pub Vec<Expression>, pub TokenRange);
pub name: String,
pub params: Vec<Expression>,
pub range: TokenRange,
pub is_macro: bool,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct IfExpression( pub struct IfExpression(
@ -184,7 +179,7 @@ pub struct LetStatement {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ImportStatement(pub Vec<(String, TokenRange)>, pub TokenRange); pub struct ImportStatement(pub Vec<String>, pub TokenRange);
#[derive(Debug)] #[derive(Debug)]
pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub TokenRange); pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub TokenRange);
@ -192,9 +187,8 @@ pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub To
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FunctionSignature { pub struct FunctionSignature {
pub name: String, pub name: String,
pub documentation: Option<String>,
pub self_kind: SelfKind, pub self_kind: SelfKind,
pub params: Vec<(String, Type, TokenRange)>, pub params: Vec<(String, Type)>,
pub return_type: Option<Type>, pub return_type: Option<Type>,
#[allow(dead_code)] #[allow(dead_code)]
pub range: TokenRange, pub range: TokenRange,
@ -202,13 +196,13 @@ pub struct FunctionSignature {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum SelfKind { pub enum SelfKind {
Owned(Type), Owned(TypeKind),
Borrow(Type), Borrow(TypeKind),
MutBorrow(Type), MutBorrow(TypeKind),
None, None,
} }
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy)]
pub enum ReturnType { pub enum ReturnType {
Soft, Soft,
Hard, Hard,
@ -217,7 +211,7 @@ pub enum ReturnType {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StructExpression { pub struct StructExpression {
name: String, name: String,
fields: Vec<(String, Expression, TokenRange)>, fields: Vec<(String, Expression)>,
range: TokenRange, range: TokenRange,
} }
@ -273,9 +267,9 @@ pub enum TopLevelStatement {
#[derive(Debug)] #[derive(Debug)]
pub struct BinopDefinition { pub struct BinopDefinition {
pub lhs: (String, Type, TokenRange), pub lhs: (String, Type),
pub op: BinaryOperator, pub op: BinaryOperator,
pub rhs: (String, Type, TokenRange), pub rhs: (String, Type),
pub return_ty: Type, pub return_ty: Type,
pub block: Block, pub block: Block,
pub signature_range: TokenRange, pub signature_range: TokenRange,

View File

@ -175,50 +175,7 @@ impl Parse for AssociatedFunctionCall {
let ty = stream.parse()?; let ty = stream.parse()?;
stream.expect(Token::Colon)?; stream.expect(Token::Colon)?;
stream.expect(Token::Colon)?; stream.expect(Token::Colon)?;
Ok(AssociatedFunctionCall(ty, stream.parse()?))
if stream.next_is_whitespace() {
stream.expecting_err_nonfatal("associated function name");
return Ok(AssociatedFunctionCall(
ty,
FunctionCallExpression {
name: String::new(),
params: Vec::new(),
range: stream.get_range_prev_curr().unwrap(),
is_macro: false,
},
));
}
match stream.parse() {
Ok(fn_call) => Ok(AssociatedFunctionCall(ty, fn_call)),
_ => {
if let Some(Token::Identifier(fn_name)) = stream.peek() {
stream.next();
stream.expected_err_nonfatal("associated function call");
Ok(AssociatedFunctionCall(
ty,
FunctionCallExpression {
name: fn_name,
params: Vec::new(),
range: stream.get_range_prev_curr().unwrap(),
is_macro: false,
},
))
} else {
stream.expected_err_nonfatal("associated function name");
Ok(AssociatedFunctionCall(
ty,
FunctionCallExpression {
name: String::new(),
params: Vec::new(),
range: stream.get_range_prev_curr().unwrap(),
is_macro: false,
},
))
}
}
}
} }
} }
@ -234,11 +191,10 @@ where
), ),
expr.0 .1, expr.0 .1,
), ),
ExpressionKind::Accessed(value_expr, index_name, range) => Expression( ExpressionKind::Accessed(value_expr, index_name) => Expression(
ExpressionKind::Accessed( ExpressionKind::Accessed(
Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)), Box::new(apply_inner(PrimaryExpression(*value_expr.clone()), fun)),
index_name.clone(), index_name.clone(),
*range,
), ),
expr.0 .1, expr.0 .1,
), ),
@ -287,9 +243,9 @@ impl Parse for PrimaryExpression {
stream.get_range().unwrap(), stream.get_range().unwrap(),
) )
} else if let Some(Token::Star) = stream.peek() { } else if let Some(Token::Star) = stream.peek() {
stream.next(); // Consume Star stream.next(); // Consume Et
apply_inner(stream.parse()?, |e| { apply_inner(stream.parse()?, |e| {
Expression(Kind::Deref(Box::new(e.0.clone())), e.0 .1) Expression(Kind::Deref(Box::new(e.0)), stream.get_range().unwrap())
}) })
} else if let Ok(unary) = stream.parse() { } else if let Ok(unary) = stream.parse() {
Expression( Expression(
@ -443,9 +399,9 @@ impl Parse for PrimaryExpression {
); );
} }
ValueIndex::Dot(val) => match val { ValueIndex::Dot(val) => match val {
DotIndexKind::StructValueIndex(name, range) => { DotIndexKind::StructValueIndex(name) => {
expr = Expression( expr = Expression(
ExpressionKind::Accessed(Box::new(expr), name, range), ExpressionKind::Accessed(Box::new(expr), name),
stream.get_range().unwrap(), stream.get_range().unwrap(),
); );
} }
@ -510,7 +466,7 @@ fn parse_binop_rhs(
if curr_token_prec < next_prec { if curr_token_prec < next_prec {
// Operator on the right of rhs has more precedence, turn // Operator on the right of rhs has more precedence, turn
// rhs into lhs for new binop // rhs into lhs for new binop
rhs = stream.parse_with(|mut st| parse_binop_rhs(&mut st, rhs, Some(op)))?; rhs = parse_binop_rhs(stream, rhs, Some(op))?;
} else { } else {
let _ = prev_operator.insert(next_op); let _ = prev_operator.insert(next_op);
} }
@ -581,20 +537,8 @@ impl Parse for BinaryOperator {
impl Parse for FunctionCallExpression { impl Parse for FunctionCallExpression {
fn parse(mut stream: TokenStream) -> Result<Self, Error> { fn parse(mut stream: TokenStream) -> Result<Self, Error> {
if let Some(Token::Identifier(name)) = stream.next() { if let Some(Token::Identifier(name)) = stream.next() {
let is_macro = if let Some(Token::Exclamation) = stream.peek() {
stream.next(); // Consume !
true
} else {
false
};
let args = stream.parse::<FunctionArgs>()?; let args = stream.parse::<FunctionArgs>()?;
Ok(FunctionCallExpression { Ok(FunctionCallExpression(name, args.0, stream.get_range().unwrap()))
name,
params: args.0,
range: stream.get_range().unwrap(),
is_macro,
})
} else { } else {
Err(stream.expected_err("identifier")?) Err(stream.expected_err("identifier")?)
} }
@ -653,7 +597,7 @@ impl Parse for LetStatement {
stream.expect(Token::Equals)?; stream.expect(Token::Equals)?;
let expression = stream.parse()?; let expression = stream.parse()?;
stream.expect_nonfatal(Token::Semi).ok(); stream.expect(Token::Semi)?;
Ok(LetStatement { Ok(LetStatement {
name: variable, name: variable,
ty, ty,
@ -674,21 +618,19 @@ impl Parse for ImportStatement {
let mut import_list = Vec::new(); let mut import_list = Vec::new();
if let Some(Token::Identifier(name)) = stream.next() { if let Some(Token::Identifier(name)) = stream.next() {
import_list.push((name, stream.get_range_prev_curr().unwrap())); import_list.push(name);
while stream.expect(Token::Colon).is_ok() && stream.expect(Token::Colon).is_ok() { while stream.expect(Token::Colon).is_ok() && stream.expect(Token::Colon).is_ok() {
if let Some(Token::Identifier(name)) = stream.peek() { if let Some(Token::Identifier(name)) = stream.next() {
stream.next(); // Consume identifier import_list.push(name);
import_list.push((name, stream.get_range_prev_curr().unwrap()));
} else { } else {
stream.expected_err_nonfatal("identifier"); Err(stream.expected_err("identifier")?)?
break;
} }
} }
} else { } else {
Err(stream.expected_err("identifier")?)? Err(stream.expected_err("identifier")?)?
} }
stream.expect_nonfatal(Token::Semi).ok(); stream.expect(Token::Semi)?;
Ok(ImportStatement(import_list, stream.get_range().unwrap())) Ok(ImportStatement(import_list, stream.get_range().unwrap()))
} }
@ -696,8 +638,6 @@ impl Parse for ImportStatement {
impl Parse for FunctionDefinition { impl Parse for FunctionDefinition {
fn parse(mut stream: TokenStream) -> Result<Self, Error> { fn parse(mut stream: TokenStream) -> Result<Self, Error> {
let documentation = stream.find_documentation();
let is_pub = if let Some(Token::PubKeyword) = stream.peek() { let is_pub = if let Some(Token::PubKeyword) = stream.peek() {
stream.next(); // Consume pub stream.next(); // Consume pub
true true
@ -706,10 +646,8 @@ impl Parse for FunctionDefinition {
}; };
stream.expect(Token::FnKeyword)?; stream.expect(Token::FnKeyword)?;
let mut signature: FunctionSignature = stream.parse()?;
signature.documentation = documentation;
Ok(FunctionDefinition( Ok(FunctionDefinition(
signature, stream.parse()?,
is_pub, is_pub,
stream.parse()?, stream.parse()?,
stream.get_range().unwrap(), stream.get_range().unwrap(),
@ -718,7 +656,7 @@ impl Parse for FunctionDefinition {
} }
#[derive(Debug)] #[derive(Debug)]
struct FunctionParam(String, Type, TokenRange); struct FunctionParam(String, Type);
impl Parse for FunctionParam { impl Parse for FunctionParam {
fn parse(mut stream: TokenStream) -> Result<Self, Error> { fn parse(mut stream: TokenStream) -> Result<Self, Error> {
@ -726,7 +664,7 @@ impl Parse for FunctionParam {
return Err(stream.expected_err("parameter name")?); return Err(stream.expected_err("parameter name")?);
}; };
stream.expect(Token::Colon)?; stream.expect(Token::Colon)?;
Ok(FunctionParam(arg_name, stream.parse()?, stream.get_range().unwrap())) Ok(FunctionParam(arg_name, stream.parse()?))
} }
} }
@ -758,18 +696,9 @@ impl Parse for SelfParam {
}; };
if name == "self" { if name == "self" {
match kind { match kind {
SelfParamKind::BorrowMut => Ok(SelfParam(SelfKind::MutBorrow(Type( SelfParamKind::BorrowMut => Ok(SelfParam(SelfKind::MutBorrow(TypeKind::Unknown))),
TypeKind::Unknown, SelfParamKind::Borrow => Ok(SelfParam(SelfKind::Borrow(TypeKind::Unknown))),
stream.get_range_prev().unwrap(), SelfParamKind::Owned => Ok(SelfParam(SelfKind::Owned(TypeKind::Unknown))),
)))),
SelfParamKind::Borrow => Ok(SelfParam(SelfKind::Borrow(Type(
TypeKind::Unknown,
stream.get_range_prev().unwrap(),
)))),
SelfParamKind::Owned => Ok(SelfParam(SelfKind::Owned(Type(
TypeKind::Unknown,
stream.get_range_prev().unwrap(),
)))),
} }
} else { } else {
Err(stream.expected_err("self parameter")?) Err(stream.expected_err("self parameter")?)
@ -788,11 +717,11 @@ impl Parse for FunctionSignature {
match &self_kind { match &self_kind {
SelfKind::None => { SelfKind::None => {
if let Ok(param) = stream.parse::<FunctionParam>() { if let Ok(param) = stream.parse::<FunctionParam>() {
params.push((param.0, param.1, param.2)); params.push((param.0, param.1));
while let Some(Token::Comma) = stream.peek() { while let Some(Token::Comma) = stream.peek() {
stream.next(); stream.next();
let param = stream.parse::<FunctionParam>()?; let param = stream.parse::<FunctionParam>()?;
params.push((param.0, param.1, param.2)); params.push((param.0, param.1));
} }
} }
} }
@ -800,7 +729,7 @@ impl Parse for FunctionSignature {
while let Some(Token::Comma) = stream.peek() { while let Some(Token::Comma) = stream.peek() {
stream.next(); stream.next();
let param = stream.parse::<FunctionParam>()?; let param = stream.parse::<FunctionParam>()?;
params.push((param.0, param.1, param.2)); params.push((param.0, param.1));
} }
} }
} }
@ -814,7 +743,6 @@ impl Parse for FunctionSignature {
Ok(FunctionSignature { Ok(FunctionSignature {
name, name,
documentation: None,
params, params,
self_kind, self_kind,
return_type, return_type,
@ -838,7 +766,7 @@ impl Parse for Block {
// if semicolon is missing. // if semicolon is missing.
if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) { if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) {
// In theory could ignore the missing semicolon.. // In theory could ignore the missing semicolon..
stream.expected_err_nonfatal("semicolon to complete statement"); return Err(stream.expected_err("semicolon to complete statement")?);
} }
statements.push(BlockLevelStatement::Expression(e)); statements.push(BlockLevelStatement::Expression(e));
@ -869,10 +797,9 @@ impl Parse for StructExpression {
let Some(Token::Identifier(name)) = stream.next() else { let Some(Token::Identifier(name)) = stream.next() else {
return Err(stream.expected_err("struct identifier")?); return Err(stream.expected_err("struct identifier")?);
}; };
stream.expect(Token::BraceOpen)?; stream.expect(Token::BraceOpen)?;
let named_list = stream.parse::<NamedFieldList<Expression>>()?; let named_list = stream.parse::<NamedFieldList<Expression>>()?;
let fields = named_list.0.into_iter().map(|f| (f.0, f.1, f.2)).collect(); let fields = named_list.0.into_iter().map(|f| (f.0, f.1)).collect();
stream.expect(Token::BraceClose)?; stream.expect(Token::BraceClose)?;
@ -949,35 +876,25 @@ impl Parse for ArrayValueIndex {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum DotIndexKind { pub enum DotIndexKind {
StructValueIndex(String, TokenRange), StructValueIndex(String),
FunctionCall(FunctionCallExpression), FunctionCall(FunctionCallExpression),
} }
impl Parse for DotIndexKind { impl Parse for DotIndexKind {
fn parse(mut stream: TokenStream) -> Result<Self, Error> { fn parse(mut stream: TokenStream) -> Result<Self, Error> {
stream.expect(Token::Dot)?; stream.expect(Token::Dot)?;
if let Some(Token::Identifier(name)) = stream.peek() { if let Some(Token::Identifier(name)) = stream.next() {
stream.next(); // Consume identifer
if let Ok(args) = stream.parse::<FunctionArgs>() { if let Ok(args) = stream.parse::<FunctionArgs>() {
Ok(Self::FunctionCall(FunctionCallExpression { Ok(Self::FunctionCall(FunctionCallExpression(
name, name,
params: args.0, args.0,
range: stream.get_range_prev().unwrap(), stream.get_range_prev().unwrap(),
is_macro: false, )))
}))
} else { } else {
Ok(Self::StructValueIndex(name, stream.get_range_prev().unwrap())) Ok(Self::StructValueIndex(name))
} }
} else { } else {
if stream.next_is_whitespace() { return Err(stream.expected_err("struct index (number)")?);
stream.expecting_err_nonfatal("struct index");
Ok(Self::StructValueIndex(
String::new(),
stream.get_range_prev_curr().unwrap(),
))
} else {
Err(stream.expecting_err("struct index")?)
}
} }
} }
} }
@ -991,7 +908,7 @@ impl Parse for BlockLevelStatement {
Some(Token::ReturnKeyword) => { Some(Token::ReturnKeyword) => {
stream.next(); stream.next();
let exp = stream.parse().ok(); let exp = stream.parse().ok();
stream.expect_nonfatal(Token::Semi).ok(); stream.expect(Token::Semi)?;
Stmt::Return(ReturnType::Hard, exp) Stmt::Return(ReturnType::Hard, exp)
} }
Some(Token::For) => { Some(Token::For) => {
@ -1056,7 +973,7 @@ impl Parse for SetStatement {
let var_ref = stream.parse()?; let var_ref = stream.parse()?;
stream.expect(Token::Equals)?; stream.expect(Token::Equals)?;
let expr = stream.parse()?; let expr = stream.parse()?;
stream.expect_nonfatal(Token::Semi).ok(); stream.expect(Token::Semi)?;
Ok(SetStatement(var_ref, expr, stream.get_range().unwrap())) Ok(SetStatement(var_ref, expr, stream.get_range().unwrap()))
} }
} }
@ -1094,13 +1011,10 @@ impl Parse for TopLevelStatement {
Ok(match stream.peek() { Ok(match stream.peek() {
Some(Token::ImportKeyword) => Stmt::Import(stream.parse()?), Some(Token::ImportKeyword) => Stmt::Import(stream.parse()?),
Some(Token::Extern) => { Some(Token::Extern) => {
let documentation = stream.find_documentation();
stream.next(); // Consume Extern stream.next(); // Consume Extern
stream.expect(Token::FnKeyword)?; stream.expect(Token::FnKeyword)?;
let mut signature: FunctionSignature = stream.parse()?; let extern_fn = Stmt::ExternFunction(stream.parse()?);
signature.documentation = documentation; stream.expect(Token::Semi)?;
let extern_fn = Stmt::ExternFunction(signature);
stream.expect_nonfatal(Token::Semi).ok();
extern_fn extern_fn
} }
Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?), Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?),
@ -1134,7 +1048,6 @@ impl Parse for BinopDefinition {
let Some(Token::Identifier(lhs_name)) = stream.next() else { let Some(Token::Identifier(lhs_name)) = stream.next() else {
return Err(stream.expected_err("lhs name")?); return Err(stream.expected_err("lhs name")?);
}; };
let lhs_range = stream.get_range_prev_curr().unwrap();
stream.expect(Token::Colon)?; stream.expect(Token::Colon)?;
let lhs_type = stream.parse()?; let lhs_type = stream.parse()?;
stream.expect(Token::ParenClose)?; stream.expect(Token::ParenClose)?;
@ -1145,7 +1058,6 @@ impl Parse for BinopDefinition {
let Some(Token::Identifier(rhs_name)) = stream.next() else { let Some(Token::Identifier(rhs_name)) = stream.next() else {
return Err(stream.expected_err("rhs name")?); return Err(stream.expected_err("rhs name")?);
}; };
let rhs_range = stream.get_range_prev_curr().unwrap();
stream.expect(Token::Colon)?; stream.expect(Token::Colon)?;
let rhs_type = stream.parse()?; let rhs_type = stream.parse()?;
stream.expect(Token::ParenClose)?; stream.expect(Token::ParenClose)?;
@ -1155,9 +1067,9 @@ impl Parse for BinopDefinition {
stream.expect(Token::Arrow)?; stream.expect(Token::Arrow)?;
Ok(BinopDefinition { Ok(BinopDefinition {
lhs: (lhs_name, lhs_type, lhs_range), lhs: (lhs_name, lhs_type),
op: operator, op: operator,
rhs: (rhs_name, rhs_type, rhs_range), rhs: (rhs_name, rhs_type),
return_ty: stream.parse()?, return_ty: stream.parse()?,
block: stream.parse()?, block: stream.parse()?,
signature_range, signature_range,
@ -1178,11 +1090,11 @@ impl Parse for AssociatedFunctionBlock {
match stream.peek() { match stream.peek() {
Some(Token::FnKeyword) | Some(Token::PubKeyword) => { Some(Token::FnKeyword) | Some(Token::PubKeyword) => {
let mut fun: FunctionDefinition = stream.parse()?; let mut fun: FunctionDefinition = stream.parse()?;
match &mut fun.0.self_kind { fun.0.self_kind = match fun.0.self_kind {
SelfKind::Owned(inner_ty) => inner_ty.0 = ty.0.clone(), SelfKind::Owned(_) => SelfKind::Owned(ty.0.clone()),
SelfKind::Borrow(inner_ty) => inner_ty.0 = ty.0.clone(), SelfKind::Borrow(_) => SelfKind::Borrow(ty.0.clone()),
SelfKind::MutBorrow(inner_ty) => inner_ty.0 = ty.0.clone(), SelfKind::MutBorrow(_) => SelfKind::MutBorrow(ty.0.clone()),
SelfKind::None => {} SelfKind::None => SelfKind::None,
}; };
functions.push(fun); functions.push(fun);
} }

View File

@ -1,10 +1,10 @@
use std::path::PathBuf; use std::path::PathBuf;
use crate::{ use crate::{
ast::{self, ReturnType}, ast::{self},
mir::{ mir::{
self, CustomTypeKey, FunctionParam, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind, self, CustomTypeKey, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind, StructField,
StructField, StructType, WhileStatement, StructType, WhileStatement,
}, },
}; };
@ -30,20 +30,12 @@ impl ast::Module {
for stmt in &self.top_level_statements { for stmt in &self.top_level_statements {
match stmt { match stmt {
Import(import) => { Import(import) => {
imports.push(mir::Import( imports.push(mir::Import(import.0.clone(), import.1.as_meta(module_id)));
import
.0
.iter()
.map(|(s, range)| (s.clone(), range.as_meta(module_id)))
.collect(),
import.1.as_meta(module_id),
));
} }
FunctionDefinition(function_def) => functions.push(function_def.into_mir(module_id)), FunctionDefinition(function_def) => functions.push(function_def.into_mir(module_id)),
ExternFunction(signature) => { ExternFunction(signature) => {
let def = mir::FunctionDefinition { let def = mir::FunctionDefinition {
name: signature.name.clone(), name: signature.name.clone(),
documentation: signature.documentation.clone(),
linkage_name: None, linkage_name: None,
is_pub: false, is_pub: false,
is_imported: false, is_imported: false,
@ -56,15 +48,9 @@ impl ast::Module {
.params .params
.iter() .iter()
.cloned() .cloned()
.map(|p| mir::FunctionParam { .map(|p| (p.0, p.1 .0.into_mir(module_id)))
name: p.0,
ty: p.1 .0.into_mir(module_id),
meta: p.2.as_meta(module_id),
})
.collect(), .collect(),
kind: mir::FunctionDefinitionKind::Extern(false), kind: mir::FunctionDefinitionKind::Extern(false),
source: Some(module_id),
signature_meta: signature.range.as_meta(module_id),
}; };
functions.push(def); functions.push(def);
} }
@ -102,17 +88,9 @@ impl ast::Module {
signature_range, signature_range,
}) => { }) => {
binops.push(mir::BinopDefinition { binops.push(mir::BinopDefinition {
lhs: mir::FunctionParam { lhs: (lhs.0.clone(), lhs.1 .0.into_mir(module_id)),
name: lhs.0.clone(),
ty: lhs.1 .0.into_mir(module_id),
meta: lhs.2.as_meta(module_id),
},
op: op.mir(), op: op.mir(),
rhs: mir::FunctionParam { rhs: (rhs.0.clone(), rhs.1 .0.into_mir(module_id)),
name: rhs.0.clone(),
ty: rhs.1 .0.into_mir(module_id),
meta: rhs.2.as_meta(module_id),
},
return_type: return_ty.0.into_mir(module_id), return_type: return_ty.0.into_mir(module_id),
fn_kind: mir::FunctionDefinitionKind::Local( fn_kind: mir::FunctionDefinitionKind::Local(
block.into_mir(module_id), block.into_mir(module_id),
@ -137,7 +115,6 @@ impl ast::Module {
imports, imports,
associated_functions, associated_functions,
functions, functions,
globals: Vec::new(),
path: self.path.clone(), path: self.path.clone(),
is_main: self.is_main, is_main: self.is_main,
tokens: self.tokens, tokens: self.tokens,
@ -152,32 +129,27 @@ impl ast::FunctionDefinition {
let mut params = Vec::new(); let mut params = Vec::new();
match &signature.self_kind { match &signature.self_kind {
ast::SelfKind::Borrow(ty) => params.push(mir::FunctionParam { ast::SelfKind::Borrow(type_kind) => params.push((
name: "self".to_owned(), "self".to_owned(),
ty: mir::TypeKind::Borrow(Box::new(ty.0.into_mir(module_id)), false), mir::TypeKind::Borrow(Box::new(type_kind.into_mir(module_id)), false),
meta: ty.1.as_meta(module_id), )),
}), ast::SelfKind::MutBorrow(type_kind) => params.push((
ast::SelfKind::MutBorrow(ty) => params.push(mir::FunctionParam { "self".to_owned(),
name: "self".to_owned(), mir::TypeKind::Borrow(Box::new(type_kind.into_mir(module_id)), true),
ty: mir::TypeKind::Borrow(Box::new(ty.0.into_mir(module_id)), true), )),
meta: ty.1.as_meta(module_id), ast::SelfKind::Owned(type_kind) => params.push(("self".to_owned(), type_kind.into_mir(module_id))),
}),
ast::SelfKind::Owned(ty) => params.push(mir::FunctionParam {
name: "self".to_owned(),
ty: ty.0.into_mir(module_id),
meta: ty.1.as_meta(module_id),
}),
ast::SelfKind::None => {} ast::SelfKind::None => {}
} }
params.extend(signature.params.iter().cloned().map(|p| FunctionParam { params.extend(
name: p.0, signature
ty: p.1 .0.into_mir(module_id), .params
meta: p.2.as_meta(module_id), .iter()
})); .cloned()
.map(|p| (p.0, p.1 .0.into_mir(module_id))),
);
mir::FunctionDefinition { mir::FunctionDefinition {
name: signature.name.clone(), name: signature.name.clone(),
documentation: signature.documentation.clone(),
linkage_name: None, linkage_name: None,
is_pub: *is_pub, is_pub: *is_pub,
is_imported: false, is_imported: false,
@ -188,8 +160,6 @@ impl ast::FunctionDefinition {
.unwrap_or(mir::TypeKind::Void), .unwrap_or(mir::TypeKind::Void),
parameters: params, parameters: params,
kind: mir::FunctionDefinitionKind::Local(block.into_mir(module_id), (range).as_meta(module_id)), kind: mir::FunctionDefinitionKind::Local(block.into_mir(module_id), (range).as_meta(module_id)),
source: Some(module_id),
signature_meta: signature.range.as_meta(module_id),
} }
} }
} }
@ -237,9 +207,8 @@ impl ast::Block {
); );
let let_statement = mir::Statement( let let_statement = mir::Statement(
StmtKind::Let(counter_var.clone(), true, start.process(module_id)), StmtKind::Let(counter_var.clone(), true, start.process(module_id)),
start.1.as_meta(module_id), counter_range.as_meta(module_id),
); );
let statement_range = counter_range.clone() + start.1 + end.1 + block.2;
let set_new = mir::Statement( let set_new = mir::Statement(
StmtKind::Set( StmtKind::Set(
@ -265,33 +234,8 @@ impl ast::Block {
), ),
counter_range.as_meta(module_id), counter_range.as_meta(module_id),
); );
let mut block = block.into_mir(module_id);
let mir_block = if let Some((ret_kind, ret_expr)) = &block.1 { block.statements.push(set_new);
if *ret_kind == ReturnType::Soft {
if let Some(ret_expr) = ret_expr {
let mir_ret = ret_expr.process(module_id);
let mut clone = block.clone();
clone.1 = None;
let mut mir_block = clone.into_mir(module_id);
mir_block
.statements
.push(mir::Statement(StmtKind::Expression(mir_ret.clone()), mir_ret.1));
mir_block.statements.push(set_new);
mir_block
} else {
let mut mir_block = block.into_mir(module_id);
mir_block.statements.push(set_new);
mir_block
}
} else {
block.into_mir(module_id)
}
} else {
let mut mir_block = block.into_mir(module_id);
mir_block.statements.push(set_new);
mir_block
};
let while_statement = mir::Statement( let while_statement = mir::Statement(
StmtKind::While(WhileStatement { StmtKind::While(WhileStatement {
condition: mir::Expression( condition: mir::Expression(
@ -304,23 +248,23 @@ impl ast::Block {
Box::new(end.process(module_id)), Box::new(end.process(module_id)),
mir::TypeKind::Vague(mir::VagueType::Unknown), mir::TypeKind::Vague(mir::VagueType::Unknown),
), ),
end.1.as_meta(module_id), counter_range.as_meta(module_id),
), ),
block: mir_block.clone(), block,
meta: (*counter_range + end.1 + block.2).as_meta(module_id), meta: self.2.as_meta(module_id),
}), }),
(*counter_range + end.1 + block.2).as_meta(module_id), self.2.as_meta(module_id),
); );
let inner_scope = StmtKind::Expression(mir::Expression( let inner_scope = StmtKind::Expression(mir::Expression(
mir::ExprKind::Block(mir::Block { mir::ExprKind::Block(mir::Block {
statements: vec![let_statement, while_statement], statements: vec![let_statement, while_statement],
return_expression: None, return_expression: None,
meta: statement_range.as_meta(module_id), meta: counter_range.as_meta(module_id) + end.1.as_meta(module_id),
}), }),
statement_range.as_meta(module_id), counter_range.as_meta(module_id) + end.1.as_meta(module_id),
)); ));
(inner_scope, statement_range) (inner_scope, self.2)
} }
ast::BlockLevelStatement::WhileLoop(expression, block) => ( ast::BlockLevelStatement::WhileLoop(expression, block) => (
StmtKind::While(WhileStatement { StmtKind::While(WhileStatement {
@ -328,7 +272,7 @@ impl ast::Block {
block: block.into_mir(module_id), block: block.into_mir(module_id),
meta: self.2.as_meta(module_id), meta: self.2.as_meta(module_id),
}), }),
expression.1 + block.2, self.2,
), ),
}; };
@ -378,11 +322,10 @@ impl ast::Expression {
mir::TypeKind::Vague(mir::VagueType::Unknown), mir::TypeKind::Vague(mir::VagueType::Unknown),
), ),
ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall { ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall {
name: fn_call_expr.name.clone(), name: fn_call_expr.0.clone(),
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(), parameters: fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(),
meta: fn_call_expr.range.as_meta(module_id), meta: fn_call_expr.2.as_meta(module_id),
is_macro: fn_call_expr.is_macro,
}), }),
ast::ExpressionKind::BlockExpr(block) => mir::ExprKind::Block(block.into_mir(module_id)), ast::ExpressionKind::BlockExpr(block) => mir::ExprKind::Block(block.into_mir(module_id)),
ast::ExpressionKind::IfExpr(if_expression) => { ast::ExpressionKind::IfExpr(if_expression) => {
@ -408,18 +351,17 @@ impl ast::Expression {
Box::new(idx_expr.process(module_id)), Box::new(idx_expr.process(module_id)),
), ),
ast::ExpressionKind::StructExpression(struct_init) => mir::ExprKind::Struct( ast::ExpressionKind::StructExpression(struct_init) => mir::ExprKind::Struct(
CustomTypeKey(struct_init.name.clone(), module_id), struct_init.name.clone(),
struct_init struct_init
.fields .fields
.iter() .iter()
.map(|(n, e, r)| (n.clone(), e.process(module_id), r.as_meta(module_id))) .map(|(n, e)| (n.clone(), e.process(module_id)))
.collect(), .collect(),
), ),
ast::ExpressionKind::Accessed(expression, name, name_range) => mir::ExprKind::Accessed( ast::ExpressionKind::Accessed(expression, name) => mir::ExprKind::Accessed(
Box::new(expression.process(module_id)), Box::new(expression.process(module_id)),
mir::TypeKind::Vague(mir::VagueType::Unknown), mir::TypeKind::Vague(mir::VagueType::Unknown),
name.clone(), name.clone(),
name_range.as_meta(module_id),
), ),
ast::ExpressionKind::Borrow(expr, mutable) => { ast::ExpressionKind::Borrow(expr, mutable) => {
mir::ExprKind::Borrow(Box::new(expr.process(module_id)), *mutable) mir::ExprKind::Borrow(Box::new(expr.process(module_id)), *mutable)
@ -467,15 +409,14 @@ impl ast::Expression {
ast::ExpressionKind::AssociatedFunctionCall(ty, fn_call_expr) => mir::ExprKind::AssociatedFunctionCall( ast::ExpressionKind::AssociatedFunctionCall(ty, fn_call_expr) => mir::ExprKind::AssociatedFunctionCall(
ty.0.into_mir(module_id), ty.0.into_mir(module_id),
mir::FunctionCall { mir::FunctionCall {
name: fn_call_expr.name.clone(), name: fn_call_expr.0.clone(),
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(), parameters: fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(),
meta: fn_call_expr.range.as_meta(module_id), meta: fn_call_expr.2.as_meta(module_id),
is_macro: fn_call_expr.is_macro,
}, },
), ),
ast::ExpressionKind::AccessCall(expression, fn_call_expr) => { ast::ExpressionKind::AccessCall(expression, fn_call_expr) => {
let mut params: Vec<_> = fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(); let mut params: Vec<_> = fn_call_expr.1.iter().map(|e| e.process(module_id)).collect();
params.insert( params.insert(
0, 0,
mir::Expression( mir::Expression(
@ -483,18 +424,13 @@ impl ast::Expression {
expression.1.as_meta(module_id), expression.1.as_meta(module_id),
), ),
); );
if fn_call_expr.is_macro {
panic!("Macros aren't supported as access-calls!");
};
mir::ExprKind::AssociatedFunctionCall( mir::ExprKind::AssociatedFunctionCall(
mir::TypeKind::Vague(mir::VagueType::Unknown), mir::TypeKind::Vague(mir::VagueType::Unknown),
mir::FunctionCall { mir::FunctionCall {
name: fn_call_expr.name.clone(), name: fn_call_expr.0.clone(),
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
parameters: params, parameters: params,
meta: fn_call_expr.range.as_meta(module_id), meta: fn_call_expr.2.as_meta(module_id),
is_macro: fn_call_expr.is_macro,
}, },
) )
} }
@ -583,7 +519,7 @@ impl ast::TypeKind {
} }
ast::TypeKind::Ptr(type_kind) => mir::TypeKind::UserPtr(Box::new(type_kind.clone().into_mir(source_mod))), ast::TypeKind::Ptr(type_kind) => mir::TypeKind::UserPtr(Box::new(type_kind.clone().into_mir(source_mod))),
ast::TypeKind::F16 => mir::TypeKind::F16, ast::TypeKind::F16 => mir::TypeKind::F16,
ast::TypeKind::F32B => mir::TypeKind::F16B, ast::TypeKind::F32B => mir::TypeKind::F32B,
ast::TypeKind::F32 => mir::TypeKind::F32, ast::TypeKind::F32 => mir::TypeKind::F32,
ast::TypeKind::F64 => mir::TypeKind::F64, ast::TypeKind::F64 => mir::TypeKind::F64,
ast::TypeKind::F80 => mir::TypeKind::F80, ast::TypeKind::F80 => mir::TypeKind::F80,

View File

@ -1,8 +1,6 @@
//! Contains relevant code for parsing tokens received from //! Contains relevant code for parsing tokens received from
//! Lexing/Tokenizing-stage. //! Lexing/Tokenizing-stage.
use std::{cell::RefCell, rc::Rc};
use crate::{ use crate::{
ast::parse::Parse, ast::parse::Parse,
lexer::{FullToken, Token}, lexer::{FullToken, Token},
@ -14,7 +12,6 @@ use crate::{
pub struct TokenStream<'a, 'b> { pub struct TokenStream<'a, 'b> {
ref_position: Option<&'b mut usize>, ref_position: Option<&'b mut usize>,
tokens: &'a [FullToken], tokens: &'a [FullToken],
errors: Rc<RefCell<Vec<Error>>>,
pub position: usize, pub position: usize,
} }
@ -23,7 +20,6 @@ impl<'a, 'b> TokenStream<'a, 'b> {
TokenStream { TokenStream {
ref_position: None, ref_position: None,
tokens, tokens,
errors: Rc::new(RefCell::new(Vec::new())),
position: 0, position: 0,
} }
} }
@ -42,42 +38,24 @@ impl<'a, 'b> TokenStream<'a, 'b> {
)) ))
} }
/// Returns expected-error for the next token in-line. Useful in conjunction
/// with [`TokenStream::peek`]
pub fn expected_err_nonfatal<T: Into<String>>(&mut self, expected: T) {
let err = match self.expected_err(expected) {
Ok(e) => e,
Err(e) => e,
};
self.errors.borrow_mut().push(err);
}
/// Returns expected-error for the previous token that was already consumed. /// Returns expected-error for the previous token that was already consumed.
/// Useful in conjunction with [`TokenStream::next`] /// Useful in conjunction with [`TokenStream::next`]
pub fn expecting_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> { pub fn expecting_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> {
let next_token = self.peek().unwrap_or(Token::Eof); let next_token = self.peek().unwrap_or(Token::Eof);
let pos = self.next_token(self.position).0;
Ok(Error::Expected( Ok(Error::Expected(
expected.into(), expected.into(),
next_token, next_token,
TokenRange { start: pos, end: pos }, TokenRange {
start: self.position,
end: self.position,
},
)) ))
} }
/// Returns expected-error for the previous token that was already consumed.
/// Useful in conjunction with [`TokenStream::next`]
pub fn expecting_err_nonfatal<T: Into<String>>(&mut self, expected: T) {
let err = match self.expecting_err(expected) {
Ok(e) => e,
Err(e) => e,
};
self.errors.borrow_mut().push(err);
}
pub fn expect(&mut self, token: Token) -> Result<(), Error> { pub fn expect(&mut self, token: Token) -> Result<(), Error> {
if let (pos, Some(peeked)) = self.next_token(self.position) { if let Some(peeked) = self.peek() {
if token == peeked.token { if token == peeked {
self.position = pos + 1; self.position += 1;
Ok(()) Ok(())
} else { } else {
Err(self.expecting_err(token)?) Err(self.expecting_err(token)?)
@ -87,62 +65,38 @@ impl<'a, 'b> TokenStream<'a, 'b> {
} }
} }
pub fn find_documentation(&mut self) -> Option<String> {
let mut from = self.position;
let mut documentation = None;
while let Some(token) = self.tokens.get(from) {
if matches!(token.token, Token::Whitespace(_) | Token::Comment(_) | Token::Doc(_)) {
from += 1;
if let Token::Doc(doctext) = &token.token {
documentation = Some(
match documentation {
Some(t) => t + " ",
None => String::new(),
} + doctext.trim(),
);
}
} else {
break;
}
}
documentation
}
pub fn expect_nonfatal(&mut self, token: Token) -> Result<(), ()> {
if let (pos, Some(peeked)) = self.next_token(self.position) {
if token == peeked.token {
self.position = pos + 1;
Ok(())
} else {
self.expecting_err_nonfatal(token);
Err(())
}
} else {
self.expecting_err_nonfatal(token);
Err(())
}
}
pub fn next(&mut self) -> Option<Token> { pub fn next(&mut self) -> Option<Token> {
let (position, token) = self.next_token(self.position); let value = if self.tokens.len() < self.position {
self.position = position + 1; None
token.map(|t| t.token.clone()) } else {
Some(self.tokens[self.position].token.clone())
};
self.position += 1;
value
} }
pub fn previous(&mut self) -> Option<Token> { pub fn previous(&mut self) -> Option<Token> {
let (_, token) = self.previous_token(self.position); if (self.position as i32 - 1) < 0 {
token.map(|t| t.token.clone()) None
} else {
Some(self.tokens[self.position - 1].token.clone())
}
} }
pub fn peek(&mut self) -> Option<Token> { pub fn peek(&mut self) -> Option<Token> {
let (_, token) = self.next_token(self.position); if self.tokens.len() < self.position {
token.map(|t| t.token.clone()) None
} else {
Some(self.tokens[self.position].token.clone())
}
} }
pub fn peek2(&mut self) -> Option<Token> { pub fn peek2(&mut self) -> Option<Token> {
let (pos2, _) = self.next_token(self.position); if self.tokens.len() < (self.position + 1) {
let (_, token) = self.next_token(pos2 + 1); None
token.map(|t| t.token.clone()) } else {
Some(self.tokens[self.position + 1].token.clone())
}
} }
/// Parse the next value of trait Parse. If the parse succeeded, the related /// Parse the next value of trait Parse. If the parse succeeded, the related
@ -207,7 +161,6 @@ impl<'a, 'b> TokenStream<'a, 'b> {
let clone = TokenStream { let clone = TokenStream {
ref_position: Some(&mut ref_pos), ref_position: Some(&mut ref_pos),
tokens: self.tokens, tokens: self.tokens,
errors: self.errors.clone(),
position, position,
}; };
@ -220,29 +173,6 @@ impl<'a, 'b> TokenStream<'a, 'b> {
} }
} }
pub fn parse_with<T, U>(&mut self, fun: T) -> Result<U, Error>
where
T: FnOnce(TokenStream) -> Result<U, Error>,
{
let mut ref_pos = self.position;
let position = self.position;
let clone = TokenStream {
ref_position: Some(&mut ref_pos),
tokens: self.tokens,
errors: self.errors.clone(),
position,
};
match fun(clone) {
Ok(res) => {
self.position = ref_pos.max(self.position);
Ok(res)
}
Err(e) => Err(e),
}
}
pub fn get_range(&self) -> Option<TokenRange> { pub fn get_range(&self) -> Option<TokenRange> {
self.ref_position.as_ref().map(|ref_pos| TokenRange { self.ref_position.as_ref().map(|ref_pos| TokenRange {
start: **ref_pos, start: **ref_pos,
@ -255,56 +185,9 @@ impl<'a, 'b> TokenStream<'a, 'b> {
pub fn get_range_prev(&self) -> Option<TokenRange> { pub fn get_range_prev(&self) -> Option<TokenRange> {
self.ref_position.as_ref().map(|ref_pos| TokenRange { self.ref_position.as_ref().map(|ref_pos| TokenRange {
start: **ref_pos, start: **ref_pos,
end: self.previous_token(self.position).0, end: self.position - 1,
}) })
} }
/// Gets range of the previous token only.
pub fn get_range_prev_curr(&self) -> Option<TokenRange> {
Some(TokenRange {
start: self.previous_token(self.position).0,
end: self.previous_token(self.position).0,
})
}
fn previous_token(&self, mut from: usize) -> (usize, Option<&'a FullToken>) {
from -= 1;
while let Some(token) = self.tokens.get(from) {
if matches!(token.token, Token::Whitespace(_) | Token::Comment(_) | Token::Doc(_)) {
from -= 1;
} else {
break;
}
}
(from, self.tokens.get(from))
}
fn next_token(&self, mut from: usize) -> (usize, Option<&'a FullToken>) {
while let Some(token) = self.tokens.get(from) {
if matches!(token.token, Token::Whitespace(_) | Token::Comment(_) | Token::Doc(_)) {
from += 1;
} else {
break;
}
}
(from, self.tokens.get(from))
}
pub fn errors(&self) -> Vec<Error> {
self.errors.borrow().clone().clone()
}
pub fn next_is_whitespace(&self) -> bool {
if let Some(token) = self.tokens.get(self.position) {
if let Token::Whitespace(_) = token.token {
true
} else {
false
}
} else {
true
}
}
} }
impl Drop for TokenStream<'_, '_> { impl Drop for TokenStream<'_, '_> {
@ -334,8 +217,8 @@ impl std::ops::Add for TokenRange {
fn add(self, rhs: Self) -> Self::Output { fn add(self, rhs: Self) -> Self::Output {
TokenRange { TokenRange {
start: self.start.min(rhs.start).min(rhs.end), start: self.start.min(rhs.start),
end: self.end.max(rhs.end).max(rhs.start), end: self.end.min(rhs.end),
} }
} }
} }

View File

@ -2,12 +2,12 @@ use std::collections::HashMap;
use reid_lib::{ use reid_lib::{
builder::{InstructionValue, TypeValue}, builder::{InstructionValue, TypeValue},
Block, Instr, Block,
}; };
use mir::{CustomTypeKey, FunctionDefinitionKind, IfExpression, TypeKind, WhileStatement}; use mir::{CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, TypeKind, WhileStatement};
use crate::mir::{self, FunctionParam, Metadata, SourceModuleId}; use crate::mir;
#[derive(Debug)] #[derive(Debug)]
pub struct Allocator { pub struct Allocator {
@ -16,18 +16,21 @@ pub struct Allocator {
pub struct AllocatorScope<'ctx, 'a> { pub struct AllocatorScope<'ctx, 'a> {
pub(super) block: &'a mut Block<'ctx>, pub(super) block: &'a mut Block<'ctx>,
pub(super) mod_id: SourceModuleId,
pub(super) type_values: &'a HashMap<CustomTypeKey, TypeValue>, pub(super) type_values: &'a HashMap<CustomTypeKey, TypeValue>,
} }
impl Allocator { impl Allocator {
pub fn from(func: &FunctionDefinitionKind, params: &Vec<FunctionParam>, scope: &mut AllocatorScope) -> Allocator { pub fn from(
func: &FunctionDefinitionKind,
params: &Vec<(String, TypeKind)>,
scope: &mut AllocatorScope,
) -> Allocator {
func.allocate(scope, params) func.allocate(scope, params)
} }
pub fn allocate(&mut self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> { pub fn allocate(&mut self, name: &String, ty: &TypeKind) -> Option<InstructionValue> {
let mut allocs = self.allocations.iter().cloned().enumerate(); let mut allocs = self.allocations.iter().cloned().enumerate();
let val = allocs.find(|a| a.1 .0 == *meta && a.1 .1 == *ty); let val = allocs.find(|a| a.1 .0 == *name && a.1 .1 == *ty);
if let Some((i, _)) = val { if let Some((i, _)) = val {
self.allocations.remove(i); self.allocations.remove(i);
} }
@ -36,13 +39,13 @@ impl Allocator {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Allocation(Metadata, TypeKind, InstructionValue); pub struct Allocation(String, TypeKind, InstructionValue);
impl mir::FunctionDefinitionKind { impl mir::FunctionDefinitionKind {
fn allocate<'ctx, 'a>( fn allocate<'ctx, 'a>(
&self, &self,
scope: &mut AllocatorScope<'ctx, 'a>, scope: &mut AllocatorScope<'ctx, 'a>,
parameters: &Vec<mir::FunctionParam>, parameters: &Vec<(String, TypeKind)>,
) -> Allocator { ) -> Allocator {
let mut allocated = Vec::new(); let mut allocated = Vec::new();
match &self { match &self {
@ -51,11 +54,11 @@ impl mir::FunctionDefinitionKind {
let allocation = scope let allocation = scope
.block .block
.build_named( .build_named(
param.name.clone(), param.0.clone(),
reid_lib::Instr::Alloca(param.ty.get_type(scope.type_values)), reid_lib::Instr::Alloca(param.1.get_type(scope.type_values)),
) )
.unwrap(); .unwrap();
allocated.push(Allocation(param.meta, param.ty.clone(), allocation)); allocated.push(Allocation(param.0.clone(), param.1.clone(), allocation));
} }
allocated.extend(block.allocate(scope)); allocated.extend(block.allocate(scope));
} }
@ -100,7 +103,7 @@ impl mir::Statement {
) )
.unwrap(); .unwrap();
allocated.push(Allocation( allocated.push(Allocation(
named_variable_ref.2, named_variable_ref.1.clone(),
named_variable_ref.0.clone(), named_variable_ref.0.clone(),
allocation, allocation,
)); ));
@ -133,42 +136,17 @@ impl mir::Expression {
allocated.extend(expr.allocate(scope)); allocated.extend(expr.allocate(scope));
allocated.extend(idx.allocate(scope)); allocated.extend(idx.allocate(scope));
} }
mir::ExprKind::Accessed(expression, ..) => { mir::ExprKind::Accessed(expression, _, _) => {
allocated.extend(expression.allocate(scope)); allocated.extend(expression.allocate(scope));
} }
mir::ExprKind::Array(expressions) => { mir::ExprKind::Array(expressions) => {
let (_, ty) = self.return_type(&Default::default(), scope.mod_id).unwrap();
let TypeKind::Array(elem_ty, _) = &ty else { panic!() };
let array_name = format!("{}.{}", elem_ty, expressions.len());
let allocation = scope
.block
.build_named(array_name, Instr::Alloca(ty.get_type(scope.type_values)))
.unwrap();
allocated.push(Allocation(self.1, ty, allocation));
for expression in expressions { for expression in expressions {
allocated.extend(expression.allocate(scope)); allocated.extend(expression.allocate(scope));
} }
} }
mir::ExprKind::Struct(key, items) => { mir::ExprKind::Struct(_, items) => {
let (_, ty) = self.return_type(&Default::default(), scope.mod_id).unwrap(); for (_, expression) in items {
let allocation = scope
.block
.build_named(key.0.clone(), Instr::Alloca(ty.get_type(scope.type_values)))
.unwrap();
allocated.push(Allocation(self.1, ty, allocation));
for (field_name, expression, _) in items {
allocated.extend(expression.allocate(scope)); allocated.extend(expression.allocate(scope));
let (_, ty) = expression.return_type(&Default::default(), scope.mod_id).unwrap();
let allocation = scope
.block
.build_named(field_name, Instr::Alloca(ty.get_type(scope.type_values)))
.unwrap();
allocated.push(Allocation(expression.1, ty, allocation));
} }
} }
mir::ExprKind::Literal(_) => {} mir::ExprKind::Literal(_) => {}
@ -176,7 +154,11 @@ impl mir::Expression {
allocated.extend(lhs.allocate(scope)); allocated.extend(lhs.allocate(scope));
allocated.extend(rhs.allocate(scope)); allocated.extend(rhs.allocate(scope));
} }
mir::ExprKind::FunctionCall(fn_call) => allocated.extend(fn_call.allocate(&fn_call.name, scope)), mir::ExprKind::FunctionCall(FunctionCall { parameters, .. }) => {
for param in parameters {
allocated.extend(param.allocate(scope));
}
}
mir::ExprKind::If(IfExpression(cond, then_ex, else_ex)) => { mir::ExprKind::If(IfExpression(cond, then_ex, else_ex)) => {
allocated.extend(cond.allocate(scope)); allocated.extend(cond.allocate(scope));
allocated.extend(then_ex.allocate(scope)); allocated.extend(then_ex.allocate(scope));
@ -192,30 +174,11 @@ impl mir::Expression {
mir::ExprKind::CastTo(expression, _) => { mir::ExprKind::CastTo(expression, _) => {
allocated.extend(expression.allocate(scope)); allocated.extend(expression.allocate(scope));
} }
mir::ExprKind::AssociatedFunctionCall(ty, fn_call) => { mir::ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => {
allocated.extend(fn_call.allocate(&format!("{}::{}", ty, fn_call.name), scope)) for param in parameters {
allocated.extend(param.allocate(scope));
}
} }
mir::ExprKind::GlobalRef(..) => {}
}
allocated
}
}
impl mir::FunctionCall {
fn allocate<'ctx, 'a>(&self, name: &String, scope: &mut AllocatorScope<'ctx, 'a>) -> Vec<Allocation> {
let mut allocated = Vec::new();
for param in &self.parameters {
allocated.extend(param.allocate(scope));
}
if self.return_type != TypeKind::Void {
let allocation = scope
.block
.build_named(name, Instr::Alloca(self.return_type.get_type(scope.type_values)))
.unwrap();
allocated.push(Allocation(self.meta, self.return_type.clone(), allocation));
} }
allocated allocated

View File

@ -1,11 +1,8 @@
use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValueKind, Instr, Type}; use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValue, Instr, Type};
use crate::{ use crate::{
codegen::{ErrorKind, StackValueKind}, codegen::{ErrorKind, StackValueKind},
mir::{ mir::{BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition, FunctionDefinitionKind, TypeKind},
implement::TypeCategory, BinaryOperator, BinopDefinition, CmpOperator, FunctionDefinition,
FunctionDefinitionKind, FunctionParam, TypeKind,
},
}; };
use super::scope::{Scope, StackValue}; use super::scope::{Scope, StackValue};
@ -26,431 +23,50 @@ const INTEGERS: [TypeKind; 10] = [
const FLOATS: [TypeKind; 7] = [ const FLOATS: [TypeKind; 7] = [
TypeKind::F16, TypeKind::F16,
TypeKind::F32, TypeKind::F32,
TypeKind::F16B, TypeKind::F32B,
TypeKind::F64, TypeKind::F64,
TypeKind::F80, TypeKind::F80,
TypeKind::F128, TypeKind::F128,
TypeKind::F128PPC, TypeKind::F128PPC,
]; ];
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum LLVMIntrinsicKind {
Max(TypeKind),
Min(TypeKind),
Abs(TypeKind),
Memcpy(TypeKind),
Sqrt(TypeKind),
PowI(TypeKind, TypeKind),
Pow(TypeKind),
Sin(TypeKind),
Cos(TypeKind),
Tan(TypeKind),
ASin(TypeKind),
ACos(TypeKind),
ATan(TypeKind),
ATan2(TypeKind),
SinH(TypeKind),
CosH(TypeKind),
TanH(TypeKind),
Log(TypeKind),
Log2(TypeKind),
Log10(TypeKind),
Copysign(TypeKind),
Floor(TypeKind),
Ceil(TypeKind),
Trunc(TypeKind),
RoundEven(TypeKind),
Round(TypeKind),
}
const INTRINSIC_IDENT: &str = "reid.intrinsic";
const MALLOC_IDENT: &str = "malloc";
macro_rules! doc {
($str:expr) => {
Some($str.to_string())
};
}
pub fn form_intrinsics() -> Vec<FunctionDefinition> { pub fn form_intrinsics() -> Vec<FunctionDefinition> {
let mut intrinsics = Vec::new(); let intrinsics = Vec::new();
intrinsics.push(FunctionDefinition {
name: MALLOC_IDENT.to_owned(),
documentation: doc!("Allocates `size` bytes and returns a `u8`-pointer."),
linkage_name: Some("malloc".to_owned()),
is_pub: false,
is_imported: true,
return_type: TypeKind::UserPtr(Box::new(TypeKind::U8)),
parameters: vec![FunctionParam {
name: "size".to_owned(),
ty: TypeKind::U64,
meta: Default::default(),
}],
kind: FunctionDefinitionKind::Extern(false),
source: None,
signature_meta: Default::default(),
});
intrinsics
}
pub fn simple_intrinsic<T: Into<String> + Clone>(
name: T,
doc: T,
params: Vec<T>,
ret: TypeKind,
intrisic: LLVMIntrinsicKind,
) -> FunctionDefinition {
FunctionDefinition {
name: name.into(),
documentation: Some(doc.into()),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: ret.clone(),
parameters: params
.iter()
.map(|p| FunctionParam::from(p.clone(), ret.clone()))
.collect(),
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM(intrisic, ret.clone()))),
source: None,
signature_meta: Default::default(),
}
}
pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
let mut intrinsics = Vec::new();
if let TypeKind::Array(_, len) = ty {
intrinsics.push(FunctionDefinition {
name: "length".to_owned(),
documentation: doc!("Returns the length of this given array"),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::U64,
parameters: vec![FunctionParam {
name: String::from("self"),
ty: TypeKind::Borrow(Box::new(ty.clone()), false),
meta: Default::default(),
}],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicConst(*len))),
source: None,
signature_meta: Default::default(),
});
}
if ty.category() == TypeCategory::Real {
intrinsics.push(simple_intrinsic(
"sqrt",
"Calculates the square-root of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Sqrt(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"sin",
"Calculates sine of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Sin(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"cos",
"Calculates cosine of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Cos(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"tan",
"Calculates tangent of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Tan(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"sinh",
"Calculates hyperbolic sine of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::SinH(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"cosh",
"Calculates hyperbolic cosine of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::CosH(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"tanh",
"Calculates hyperbolic tangent of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::TanH(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"asin",
"Calculates arcsine of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::ASin(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"acos",
"Calculates arccosine of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::ACos(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"atan",
"Calculates arctangent of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::ATan(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"atan2",
"Calculates 2-argument arctangent of `value`",
vec!["self", "other"],
ty.clone(),
LLVMIntrinsicKind::ATan2(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"log",
"Returns logₑ of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Log(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"log2",
"Returns log₂ of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Log2(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"log10",
"Returns log₁₀ of `value`",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Log10(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"floor",
"Rounds `value` towards negative infinity.",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Floor(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"ceil",
"Rounds `value` towards positive infinity.",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Ceil(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"trunc",
"Truncates `value` to the integer nearest to `0`.",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Trunc(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"round",
"Rounds `value` to the closest even integer.",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::Round(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"even",
"Rounds `value` to the closest even integer.",
vec!["self"],
ty.clone(),
LLVMIntrinsicKind::RoundEven(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"pow",
"Returns `value` raised to the exponent of `exponent`.",
vec!["self", "exponent"],
ty.clone(),
LLVMIntrinsicKind::Pow(ty.clone()),
));
intrinsics.push(FunctionDefinition {
name: "powi".to_owned(),
documentation: doc!("Returns `value` raised to the exponent of `exponent`."),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: ty.clone(),
parameters: vec![
FunctionParam {
name: String::from("self"),
ty: ty.clone(),
meta: Default::default(),
},
FunctionParam {
name: String::from("exponent"),
ty: TypeKind::U32,
meta: Default::default(),
},
],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicLLVM(
LLVMIntrinsicKind::PowI(ty.clone(), TypeKind::U32),
ty.clone(),
))),
source: None,
signature_meta: Default::default(),
});
}
match ty.category() {
TypeCategory::Integer | TypeCategory::Real | TypeCategory::Bool => {
intrinsics.push(simple_intrinsic(
"max",
"Returns the larger of `a` and `b`.",
vec!["self", "other"],
ty.clone(),
LLVMIntrinsicKind::Max(ty.clone()),
));
intrinsics.push(simple_intrinsic(
"min",
"Returns the smaller of `a` and `b`.",
vec!["self", "other"],
ty.clone(),
LLVMIntrinsicKind::Min(ty.clone()),
));
if ty.signed() {
intrinsics.push(FunctionDefinition {
name: "abs".to_owned(),
documentation: doc!("Returns the absolute value of `value`."),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: ty.clone(),
parameters: vec![FunctionParam {
name: String::from("self"),
ty: ty.clone(),
meta: Default::default(),
}],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleUnaryInstr({
let ty = ty.clone();
|scope, param| {
let intrinsic = scope.get_intrinsic(LLVMIntrinsicKind::Abs(ty));
let constant = scope.block.build(Instr::Constant(ConstValueKind::Bool(false))).unwrap();
let value = scope
.block
.build(Instr::FunctionCall(intrinsic, vec![param, constant]))
.unwrap();
value
}
}))),
source: None,
signature_meta: Default::default(),
});
}
}
_ => {}
}
intrinsics.push(FunctionDefinition {
name: "sizeof".to_owned(),
documentation: doc!("Simply returns the size of type `T` in bytes."),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::U64,
parameters: Vec::new(),
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSizeOf(ty.clone()))),
source: None,
signature_meta: Default::default(),
});
intrinsics.push(FunctionDefinition {
name: "malloc".to_owned(),
documentation: doc!("Allocates `T::sizeof() * size` bytes and returns a pointer to `T`."),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::UserPtr(Box::new(ty.clone())),
parameters: vec![FunctionParam {
name: String::from("size"),
ty: TypeKind::U64,
meta: Default::default(),
}],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMalloc(ty.clone()))),
source: None,
signature_meta: Default::default(),
});
intrinsics.push(FunctionDefinition {
name: "memcpy".to_owned(),
documentation: doc!(
"Copies `T::sizeof() * size` bytes from pointer `source` to pointer
`destination`."
),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::Void,
parameters: vec![
FunctionParam {
name: String::from("destination"),
ty: TypeKind::UserPtr(Box::new(ty.clone())),
meta: Default::default(),
},
FunctionParam {
name: String::from("source"),
ty: TypeKind::UserPtr(Box::new(ty.clone())),
meta: Default::default(),
},
FunctionParam {
name: String::from("length"),
ty: TypeKind::U64,
meta: Default::default(),
},
],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicMemcpy(ty.clone()))),
source: None,
signature_meta: Default::default(),
});
intrinsics.push(FunctionDefinition {
name: "null".to_owned(),
documentation: doc!("Returns a null-pointer of type `T`."),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::UserPtr(Box::new(ty.clone())),
parameters: Vec::new(),
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicNullPtr(ty.clone()))),
source: None,
signature_meta: Default::default(),
});
intrinsics.push(FunctionDefinition {
name: "is_null".to_owned(),
documentation: doc!("Returns a boolean representing if `val` is a nullptr or not."),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::Bool,
parameters: vec![FunctionParam {
name: "value".to_string(),
ty: TypeKind::UserPtr(Box::new(ty.clone())),
meta: Default::default(),
}],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicIsNull)),
source: None,
signature_meta: Default::default(),
});
intrinsics intrinsics
} }
pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> { pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> {
get_intrinsic_assoc_functions(ty).into_iter().find(|f| f.name == name) match name {
"sizeof" => Some(FunctionDefinition {
name: "sizeof".to_owned(),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::U64,
parameters: Vec::new(),
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSizeOf(ty.clone()))),
}),
"alloca" => Some(FunctionDefinition {
name: "alloca".to_owned(),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::UserPtr(Box::new(ty.clone())),
parameters: vec![(String::from("size"), TypeKind::U64)],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicAlloca(ty.clone()))),
}),
"null" => Some(FunctionDefinition {
name: "null".to_owned(),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::UserPtr(Box::new(ty.clone())),
parameters: Vec::new(),
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicNullPtr(ty.clone()))),
}),
_ => None,
}
} }
fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
@ -458,19 +74,11 @@ where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{ {
BinopDefinition { BinopDefinition {
lhs: FunctionParam { lhs: ("lhs".to_owned(), ty.clone()),
name: "lhs".to_owned(),
ty: ty.clone(),
meta: Default::default(),
},
op, op,
rhs: FunctionParam { rhs: ("rhs".to_owned(), ty.clone()),
name: "rhs".to_owned(),
ty: ty.clone(),
meta: Default::default(),
},
return_type: ty.clone(), return_type: ty.clone(),
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))), fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
meta: Default::default(), meta: Default::default(),
exported: false, exported: false,
} }
@ -481,19 +89,11 @@ where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{ {
BinopDefinition { BinopDefinition {
lhs: FunctionParam { lhs: ("lhs".to_owned(), lhs.clone()),
name: "lhs".to_owned(),
ty: lhs.clone(),
meta: Default::default(),
},
op, op,
rhs: FunctionParam { rhs: ("rhs".to_owned(), rhs.clone()),
name: "rhs".to_owned(),
ty: rhs.clone(),
meta: Default::default(),
},
return_type: lhs.clone(), return_type: lhs.clone(),
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleBinaryInstr(fun))), fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSimpleInstr(fun))),
meta: Default::default(), meta: Default::default(),
exported: false, exported: false,
} }
@ -504,17 +104,9 @@ where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{ {
BinopDefinition { BinopDefinition {
lhs: FunctionParam { lhs: ("lhs".to_owned(), ty.clone()),
name: "lhs".to_owned(),
ty: ty.clone(),
meta: Default::default(),
},
op, op,
rhs: FunctionParam { rhs: ("rhs".to_owned(), ty.clone()),
name: "rhs".to_owned(),
ty: ty.clone(),
meta: Default::default(),
},
return_type: TypeKind::Bool, return_type: TypeKind::Bool,
fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))), fn_kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicBooleanInstr(fun))),
meta: Default::default(), meta: Default::default(),
@ -581,17 +173,26 @@ pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
scope.block.build(Instr::XOr(lhs, rhs)).unwrap() scope.block.build(Instr::XOr(lhs, rhs)).unwrap()
})); }));
if ty.signed() { if ty.signed() {
intrinsics.push(complex_binop_def(BitshiftRight, &ty, &ty, |scope, lhs, rhs| { intrinsics.push(complex_binop_def(
scope.block.build(Instr::ShiftRightArithmetic(lhs, rhs)).unwrap() BitshiftRight,
})); &ty,
&TypeKind::U64,
|scope, lhs, rhs| scope.block.build(Instr::ShiftRightArithmetic(lhs, rhs)).unwrap(),
));
} else { } else {
intrinsics.push(complex_binop_def(BitshiftRight, &ty, &ty, |scope, lhs, rhs| { intrinsics.push(complex_binop_def(
scope.block.build(Instr::ShiftRightLogical(lhs, rhs)).unwrap() BitshiftRight,
})); &ty,
&TypeKind::U64,
|scope, lhs, rhs| scope.block.build(Instr::ShiftRightLogical(lhs, rhs)).unwrap(),
));
} }
intrinsics.push(complex_binop_def(BitshiftLeft, &ty, &ty, |scope, lhs, rhs| { intrinsics.push(complex_binop_def(
scope.block.build(Instr::ShiftLeft(lhs, rhs)).unwrap() BitshiftLeft,
})); &ty,
&TypeKind::U64,
|scope, lhs, rhs| scope.block.build(Instr::ShiftLeft(lhs, rhs)).unwrap(),
));
} }
for ty in INTEGERS.iter().chain(&[TypeKind::Bool, TypeKind::Char]) { for ty in INTEGERS.iter().chain(&[TypeKind::Bool, TypeKind::Char]) {
intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| { intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
@ -614,22 +215,17 @@ pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| { intrinsics.push(simple_binop_def(Div, &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FDiv(lhs, rhs)).unwrap() scope.block.build(Instr::FDiv(lhs, rhs)).unwrap()
})); }));
intrinsics.push(simple_binop_def(Mod, &ty, { intrinsics.push(simple_binop_def(Mod, &ty, |scope, lhs, rhs| {
let ty = ty.clone(); let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap();
|scope, lhs, rhs| { let mul = scope.block.build(Instr::Mul(rhs, div)).unwrap();
let div = scope.block.build(Instr::FDiv(lhs, rhs)).unwrap(); scope.block.build(Instr::Sub(lhs, mul)).unwrap()
let fun = scope.get_intrinsic(LLVMIntrinsicKind::Trunc(ty));
let div_truncated = scope.block.build(Instr::FunctionCall(fun, vec![div])).unwrap();
let mul = scope.block.build(Instr::FMul(rhs, div_truncated)).unwrap();
scope.block.build(Instr::FSub(lhs, mul)).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::EQ), &ty, |scope, lhs, rhs| { intrinsics.push(boolean_binop_def(Cmp(CmpOperator::EQ), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FCmp(CmpPredicate::EQ, lhs, rhs)).unwrap() 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| { intrinsics.push(boolean_binop_def(Cmp(CmpOperator::GT), &ty, |scope, lhs, rhs| {
scope.block.build(Instr::FCmp(CmpPredicate::GT, lhs, rhs)).unwrap() scope.block.build(Instr::FCmp(CmpPredicate::GT, lhs, rhs)).unwrap()
})); }));
@ -675,37 +271,12 @@ macro_rules! intrinsic_debug {
} }
#[derive(Clone)] #[derive(Clone)]
pub struct IntrinsicSimpleUnaryInstr<T>(T) pub struct IntrinsicSimpleInstr<T>(T)
where
T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue;
impl<T> std::fmt::Debug for IntrinsicSimpleUnaryInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("IntrinsicSimpleUnaryInstr").finish()
}
}
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleUnaryInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue) -> InstructionValue,
{
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let param = params.get(0).unwrap();
let instr = self.clone().0(scope, param.instr());
Ok(StackValue(StackValueKind::Literal(instr), param.1.clone()))
}
}
#[derive(Clone)]
pub struct IntrinsicSimpleBinaryInstr<T>(T)
where where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue; T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
intrinsic_debug!(IntrinsicSimpleBinaryInstr<T>, "IntrinsicSimpleBinaryInstr"); intrinsic_debug!(IntrinsicSimpleInstr<T>, "IntrinsicSimpleInstr");
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleBinaryInstr<T> impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T>
where where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue, T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{ {
@ -741,60 +312,21 @@ impl IntrinsicFunction for IntrinsicSizeOf {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
let instr = scope let instr = scope
.block .block
.build(Instr::Constant(reid_lib::ConstValueKind::U64( .build(Instr::Constant(reid_lib::ConstValue::U64(self.0.size_of())))
self.0.size_of(&scope.type_map) / 8,
)))
.unwrap(); .unwrap();
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone())) Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct IntrinsicMemcpy(TypeKind); pub struct IntrinsicAlloca(TypeKind);
impl IntrinsicFunction for IntrinsicMemcpy { impl IntrinsicFunction for IntrinsicAlloca {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let dest = params.get(0).unwrap();
let src = params.get(1).unwrap();
let length = params.get(2).unwrap();
let intrinsic = scope.get_intrinsic(LLVMIntrinsicKind::Memcpy(TypeKind::UserPtr(Box::new(self.0.clone()))));
let sizeof = scope
.block
.build(Instr::Constant(ConstValueKind::U64(
self.0.size_of(&scope.type_map) / 8,
)))
.unwrap();
let bytes = scope.block.build(Instr::Mul(sizeof, length.instr())).unwrap();
let params = vec![
dest.instr(),
src.instr(),
bytes,
scope.block.build(Instr::Constant(ConstValueKind::Bool(false))).unwrap(),
];
let value = scope.block.build(Instr::FunctionCall(intrinsic, params)).unwrap();
Ok(StackValue(StackValueKind::Literal(value), TypeKind::Void))
}
}
#[derive(Clone, Debug)]
pub struct IntrinsicMalloc(TypeKind);
impl IntrinsicFunction for IntrinsicMalloc {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let amount = params.get(0).unwrap(); let amount = params.get(0).unwrap();
let function = scope let instr = scope
.block .block
.find_function(&format!("{}.{}", INTRINSIC_IDENT, MALLOC_IDENT)) .build(Instr::ArrayAlloca(self.0.get_type(scope.type_values), amount.instr()))
.unwrap(); .unwrap();
let sizeof = scope
.block
.build(Instr::Constant(ConstValueKind::U64(
self.0.size_of(&scope.type_map) / 8,
)))
.unwrap();
let bytes = scope.block.build(Instr::Mul(sizeof, amount.instr())).unwrap();
let instr = scope.block.build(Instr::FunctionCall(function, vec![bytes])).unwrap();
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone())) Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
} }
} }
@ -803,7 +335,7 @@ impl IntrinsicFunction for IntrinsicMalloc {
pub struct IntrinsicNullPtr(TypeKind); pub struct IntrinsicNullPtr(TypeKind);
impl IntrinsicFunction for IntrinsicNullPtr { impl IntrinsicFunction for IntrinsicNullPtr {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
let zero = scope.block.build(Instr::Constant(ConstValueKind::I8(0))).unwrap(); let zero = scope.block.build(Instr::Constant(ConstValue::I8(0))).unwrap();
let instr = scope let instr = scope
.block .block
.build(Instr::IntToPtr( .build(Instr::IntToPtr(
@ -818,42 +350,6 @@ impl IntrinsicFunction for IntrinsicNullPtr {
} }
} }
#[derive(Clone, Debug)]
pub struct IntrinsicIsNull;
impl IntrinsicFunction for IntrinsicIsNull {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let val = params.get(0).unwrap().instr();
let instr = scope.block.build(Instr::IsNull(val)).unwrap();
Ok(StackValue(StackValueKind::Literal(instr), TypeKind::Bool))
}
}
#[derive(Clone, Debug)]
pub struct IntrinsicConst(u64);
impl IntrinsicFunction for IntrinsicConst {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
let zero = scope.block.build(Instr::Constant(ConstValueKind::U64(self.0))).unwrap();
Ok(StackValue(StackValueKind::Literal(zero), TypeKind::U64))
}
}
#[derive(Clone, Debug)]
pub struct IntrinsicLLVM(LLVMIntrinsicKind, TypeKind);
impl IntrinsicFunction for IntrinsicLLVM {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let intrinsic = scope.get_intrinsic(self.0.clone());
let value = scope
.block
.build(Instr::FunctionCall(
intrinsic,
params.iter().map(|p| p.instr()).collect(),
))
.unwrap();
Ok(StackValue(StackValueKind::Literal(value), self.1.clone()))
}
}
// impl IntrinsicFunction for IntrinsicIAdd { // impl IntrinsicFunction for IntrinsicIAdd {
// fn codegen<'ctx, 'a>( // fn codegen<'ctx, 'a>(
// &self, // &self,

View File

@ -1,20 +1,14 @@
use std::{ use std::{cell::RefCell, collections::HashMap, rc::Rc};
cell::RefCell,
collections::{HashMap, HashSet},
rc::Rc,
};
use allocator::{Allocator, AllocatorScope}; use allocator::{Allocator, AllocatorScope};
use intrinsics::*; use intrinsics::*;
use reid_lib::{ use reid_lib::{
builder::ConstantValue,
compile::CompiledModule, compile::CompiledModule,
debug_information::{ debug_information::{
DebugFileData, DebugLexicalScope, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind, DebugFileData, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind, DebugSubprogramData,
DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DwarfFlags, DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DwarfFlags, InstructionDebugRecordData,
InstructionDebugRecordData,
}, },
CmpPredicate, ConstValueKind, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct, CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct,
TerminatorKind as Term, Type, TerminatorKind as Term, Type,
}; };
use scope::*; use scope::*;
@ -24,8 +18,8 @@ use crate::{
self, self,
implement::TypeCategory, implement::TypeCategory,
pass::{AssociatedFunctionKey, BinopKey}, pass::{AssociatedFunctionKey, BinopKey},
CustomTypeKey, FunctionCall, FunctionDefinitionKind, FunctionParam, NamedVariableRef, SourceModuleId, CustomTypeKey, FunctionCall, FunctionDefinitionKind, NamedVariableRef, SourceModuleId, StructField, StructType,
StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
}, },
util::try_all, util::try_all,
}; };
@ -62,12 +56,10 @@ impl mir::Context {
let mut modules = HashMap::new(); let mut modules = HashMap::new();
let mut modules_sorted = self.modules.iter().map(|(_, m)| m).collect::<Vec<_>>(); let mut modules_sorted = self.modules.iter().map(|(_, m)| m).collect::<Vec<_>>();
modules_sorted.sort_by(|m1, m2| m2.module_id.cmp(&m1.module_id)); modules_sorted.sort_by(|m1, m2| m2.module_id.cmp(&m1.module_id));
for module in &modules_sorted {
modules.insert(module.module_id, *module);
}
for module in &modules_sorted { for module in &modules_sorted {
module.codegen(context, modules.clone())?; let codegen = module.codegen(context, modules.clone())?;
modules.insert(module.module_id, codegen);
} }
Ok(CodegenContext { context }) Ok(CodegenContext { context })
} }
@ -102,45 +94,11 @@ impl Default for State {
} }
} }
impl mir::GlobalKind {
fn codegen<'ctx>(
&'ctx self,
context: &'ctx Context,
types: &HashMap<CustomTypeKey, reid_lib::builder::TypeValue>,
module: &Module,
) -> Result<(ConstantValue, TypeKind), ErrorKind> {
Ok(match self {
mir::GlobalKind::Literal(literal) => (module.add_constant(literal.as_const_kind()), literal.as_type()),
mir::GlobalKind::Array(globals) => {
let values = try_all(globals.into_iter().map(|g| g.codegen(context, types, module)).collect())
.map_err(|e| e.first().unwrap().clone())?;
let elem_ty = values.iter().map(|(_, t)| t.clone()).next().unwrap_or(TypeKind::Void);
let values = values.iter().map(|(v, _)| *v).collect::<Vec<_>>();
(
module.add_constant(ConstValueKind::Array(values, elem_ty.get_type(&types))),
TypeKind::Array(Box::new(elem_ty), globals.len() as u64),
)
}
})
}
}
fn get_typekey(ty: &TypeKind) -> Option<CustomTypeKey> {
match ty {
TypeKind::Array(type_kind, _) => get_typekey(type_kind.as_ref()),
TypeKind::CustomType(custom_type_key) => Some(custom_type_key.clone()),
TypeKind::Borrow(type_kind, _) => get_typekey(type_kind.as_ref()),
TypeKind::UserPtr(type_kind) => get_typekey(type_kind.as_ref()),
TypeKind::CodegenPtr(type_kind) => get_typekey(type_kind.as_ref()),
_ => None,
}
}
impl mir::Module { impl mir::Module {
fn codegen<'ctx>( fn codegen<'ctx>(
&'ctx self, &'ctx self,
context: &'ctx Context, context: &'ctx Context,
modules: HashMap<SourceModuleId, &mir::Module>, modules: HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
) -> Result<ModuleCodegen<'ctx>, ErrorKind> { ) -> Result<ModuleCodegen<'ctx>, ErrorKind> {
let mut module = context.module(&self.name, self.is_main); let mut module = context.module(&self.name, self.is_main);
let tokens = &self.tokens; let tokens = &self.tokens;
@ -160,7 +118,6 @@ impl mir::Module {
let mut types = HashMap::new(); let mut types = HashMap::new();
let mut type_values = HashMap::new(); let mut type_values = HashMap::new();
let mut debug_types = HashMap::new(); let mut debug_types = HashMap::new();
let mut type_map = HashMap::new();
macro_rules! insert_debug { macro_rules! insert_debug {
($kind:expr) => { ($kind:expr) => {
@ -170,7 +127,8 @@ impl mir::Module {
&compile_unit, &compile_unit,
&debug, &debug,
&debug_types, &debug_types,
&type_map, &type_values,
&types,
self.module_id, self.module_id,
&self.tokens, &self.tokens,
&modules, &modules,
@ -193,49 +151,20 @@ impl mir::Module {
insert_debug!(&TypeKind::Void); insert_debug!(&TypeKind::Void);
insert_debug!(&TypeKind::Char); insert_debug!(&TypeKind::Char);
// Since we know by this point that no types are recursive, we can let mut typedefs = self.typedefs.clone();
// somewhat easily sort the type-definitions such that we can process typedefs.sort_by(|a, b| b.source_module.cmp(&a.source_module));
// the ones with no depencencies first, and later the ones that depend
// on the earlier ones.
let mut typekeys_seen: HashSet<CustomTypeKey> = HashSet::new();
let mut typedefs_sorted: Vec<TypeDefinition> = Vec::new();
let mut typedefs_left = self.typedefs.clone();
while let Some(typedef) = typedefs_left.pop() {
let is_ok = match &typedef.kind {
TypeDefinitionKind::Struct(StructType(fields)) => {
let mut field_iter = fields.iter();
loop {
if let Some(field) = field_iter.next() {
if let Some(key) = get_typekey(&field.1) {
if !typekeys_seen.contains(&key) {
break false;
}
}
} else {
break true;
}
}
}
};
if is_ok { for typedef in typedefs {
typekeys_seen.insert(CustomTypeKey(typedef.name.clone(), typedef.source_module));
typedefs_sorted.push(typedef);
} else {
typedefs_left.insert(0, typedef.clone());
}
}
for typedef in typedefs_sorted {
let type_key = CustomTypeKey(typedef.name.clone(), typedef.source_module); let type_key = CustomTypeKey(typedef.name.clone(), typedef.source_module);
type_map.insert(type_key.clone(), typedef.clone());
let type_value = match &typedef.kind { let type_value = match &typedef.kind {
TypeDefinitionKind::Struct(StructType(fields)) => { TypeDefinitionKind::Struct(StructType(fields)) => {
module.custom_type(CustomTypeKind::NamedStruct(NamedStruct( module.custom_type(CustomTypeKind::NamedStruct(NamedStruct(
typedef.name.clone(), typedef.name.clone(),
fields fields
.iter() .iter()
// TODO: Reorder custom-type definitions such that
// inner types get evaluated first. Otherwise this
// will cause a panic!
.map(|StructField(_, t, _)| t.get_type(&type_values)) .map(|StructField(_, t, _)| t.get_type(&type_values))
.collect(), .collect(),
))) )))
@ -243,47 +172,22 @@ impl mir::Module {
}; };
types.insert(type_value, typedef.clone()); types.insert(type_value, typedef.clone());
type_values.insert(type_key.clone(), type_value); type_values.insert(type_key.clone(), type_value);
insert_debug!(&TypeKind::CustomType(type_key.clone())); insert_debug!(&TypeKind::CustomType(type_key.clone()));
} }
let mut globals = HashMap::new();
for global in &self.globals {
let (const_value, _) = global.kind.codegen(context, &type_values, &module)?;
globals.insert(global.name.clone(), module.add_global(&global.name, const_value));
}
let mut functions = HashMap::new(); let mut functions = HashMap::new();
for function in &self.functions { for function in &self.functions {
let param_types: Vec<Type> = function let param_types: Vec<Type> = function
.parameters .parameters
.iter() .iter()
.map(|FunctionParam { ty, .. }| ty.get_type(&type_values)) .map(|(_, p)| p.get_type(&type_values))
.collect(); .collect();
let is_main = self.is_main && function.name == "main"; let is_main = self.is_main && function.name == "main";
let module_prefix = if let Some(module) = function.source {
if module == self.module_id {
format!("reid.{}.", self.name)
} else {
format!("reid.{}.", modules.get(&module).unwrap().name)
}
} else {
format!("reid.intrinsic.")
};
let linkage_name = function.linkage_name.clone().unwrap_or(function.name.clone());
let full_name = format!(
"{}{}",
module_prefix,
function.linkage_name.clone().unwrap_or(function.name.clone())
);
let func = match &function.kind { let func = match &function.kind {
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function( mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
&full_name, &function.linkage_name.clone().unwrap_or(function.name.clone()),
None,
function.return_type.get_type(&type_values), function.return_type.get_type(&type_values),
param_types, param_types,
FunctionFlags { FunctionFlags {
@ -294,16 +198,7 @@ impl mir::Module {
}, },
)), )),
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function( mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
&full_name, &function.linkage_name.clone().unwrap_or(function.name.clone()),
if function.source == None {
Some(function.linkage_name.clone().unwrap())
} else {
if !*imported {
Some(linkage_name.clone())
} else {
None
}
},
function.return_type.get_type(&type_values), function.return_type.get_type(&type_values),
param_types, param_types,
FunctionFlags { FunctionFlags {
@ -326,24 +221,13 @@ impl mir::Module {
let param_types: Vec<Type> = function let param_types: Vec<Type> = function
.parameters .parameters
.iter() .iter()
.map(|FunctionParam { ty, .. }| ty.get_type(&type_values)) .map(|(_, p)| p.get_type(&type_values))
.collect(); .collect();
let is_main = self.is_main && function.name == "main"; let is_main = self.is_main && function.name == "main";
let module_prefix = if let Some(module_id) = function.source {
if module_id == self.module_id {
format!("reid.{}.", self.name)
} else {
format!("reid.{}.", modules.get(&module_id).unwrap().name)
}
} else {
format!("reid.intrinsic.")
};
let full_name = format!("{}{}::{}", module_prefix, ty, function.name);
let func = match &function.kind { let func = match &function.kind {
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function( mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
&full_name, &format!("{}::{}", ty, function.name),
None,
function.return_type.get_type(&type_values), function.return_type.get_type(&type_values),
param_types, param_types,
FunctionFlags { FunctionFlags {
@ -354,8 +238,7 @@ impl mir::Module {
}, },
)), )),
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function( mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
&full_name, &function.linkage_name.clone().unwrap_or(function.name.clone()),
None,
function.return_type.get_type(&type_values), function.return_type.get_type(&type_values),
param_types, param_types,
FunctionFlags { FunctionFlags {
@ -379,11 +262,11 @@ impl mir::Module {
for binop in &self.binop_defs { for binop in &self.binop_defs {
let binop_fn_name = format!( let binop_fn_name = format!(
"binop.{}.{:?}.{}.{}", "binop.{}.{:?}.{}.{}",
binop.lhs.ty, binop.op, binop.rhs.ty, binop.return_type binop.lhs.1, binop.op, binop.rhs.1, binop.return_type
); );
binops.insert( binops.insert(
BinopKey { BinopKey {
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()), params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
operator: binop.op, operator: binop.op,
}, },
StackBinopDefinition { StackBinopDefinition {
@ -393,9 +276,8 @@ impl mir::Module {
FunctionDefinitionKind::Local(..) => { FunctionDefinitionKind::Local(..) => {
let ir_function = module.function( let ir_function = module.function(
&binop_fn_name, &binop_fn_name,
None,
binop.return_type.get_type(&type_values), binop.return_type.get_type(&type_values),
vec![binop.lhs.ty.get_type(&type_values), binop.rhs.ty.get_type(&type_values)], vec![binop.lhs.1.get_type(&type_values), binop.rhs.1.get_type(&type_values)],
FunctionFlags { FunctionFlags {
is_pub: binop.exported, is_pub: binop.exported,
is_imported: binop.exported, is_imported: binop.exported,
@ -410,7 +292,6 @@ impl mir::Module {
&mut AllocatorScope { &mut AllocatorScope {
block: &mut entry, block: &mut entry,
type_values: &type_values, type_values: &type_values,
mod_id: self.module_id,
}, },
); );
@ -426,8 +307,6 @@ impl mir::Module {
functions: &functions, functions: &functions,
types: &types, types: &types,
type_values: &type_values, type_values: &type_values,
type_map: &type_map,
globals: &globals,
stack_values: HashMap::new(), stack_values: HashMap::new(),
debug: Some(Debug { debug: Some(Debug {
info: &debug, info: &debug,
@ -436,7 +315,6 @@ impl mir::Module {
}), }),
binops: &binops, binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())),
}; };
binop binop
@ -462,9 +340,8 @@ impl mir::Module {
} }
FunctionDefinitionKind::Extern(imported) => ScopeFunctionKind::UserGenerated(module.function( FunctionDefinitionKind::Extern(imported) => ScopeFunctionKind::UserGenerated(module.function(
&binop_fn_name, &binop_fn_name,
None,
binop.return_type.get_type(&type_values), binop.return_type.get_type(&type_values),
vec![binop.lhs.ty.get_type(&type_values), binop.rhs.ty.get_type(&type_values)], vec![binop.lhs.1.get_type(&type_values), binop.rhs.1.get_type(&type_values)],
FunctionFlags { FunctionFlags {
is_extern: true, is_extern: true,
is_imported: *imported, is_imported: *imported,
@ -489,7 +366,6 @@ impl mir::Module {
&mut AllocatorScope { &mut AllocatorScope {
block: &mut entry, block: &mut entry,
type_values: &type_values, type_values: &type_values,
mod_id: self.module_id,
}, },
); );
@ -505,17 +381,14 @@ impl mir::Module {
functions: &functions, functions: &functions,
types: &types, types: &types,
type_values: &type_values, type_values: &type_values,
type_map: &type_map,
stack_values: HashMap::new(), stack_values: HashMap::new(),
debug: Some(Debug { debug: Some(Debug {
info: &debug, info: &debug,
scope: compile_unit.clone(), scope: compile_unit.clone(),
types: &debug_types, types: &debug_types,
}), }),
globals: &globals,
binops: &binops, binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())),
}; };
mir_function mir_function
@ -552,7 +425,6 @@ impl mir::Module {
&mut AllocatorScope { &mut AllocatorScope {
block: &mut entry, block: &mut entry,
type_values: &type_values, type_values: &type_values,
mod_id: self.module_id,
}, },
); );
@ -568,17 +440,14 @@ impl mir::Module {
functions: &functions, functions: &functions,
types: &types, types: &types,
type_values: &type_values, type_values: &type_values,
type_map: &type_map,
stack_values: HashMap::new(), stack_values: HashMap::new(),
debug: Some(Debug { debug: Some(Debug {
info: &debug, info: &debug,
scope: compile_unit.clone(), scope: compile_unit.clone(),
types: &debug_types, types: &debug_types,
}), }),
globals: &globals,
binops: &binops, binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
llvm_intrinsics: Rc::new(RefCell::new(HashMap::new())),
}; };
mir_function mir_function
@ -612,7 +481,7 @@ impl FunctionDefinitionKind {
name: String, name: String,
is_pub: bool, is_pub: bool,
scope: &mut Scope, scope: &mut Scope,
parameters: &Vec<FunctionParam>, parameters: &Vec<(String, TypeKind)>,
return_type: &TypeKind, return_type: &TypeKind,
ir_function: &Function, ir_function: &Function,
debug_location: Option<DebugLocation>, debug_location: Option<DebugLocation>,
@ -656,31 +525,57 @@ impl FunctionDefinitionKind {
} }
// Compile actual IR part // Compile actual IR part
for (i, p) in parameters.iter().enumerate() { for (i, (p_name, p_ty)) in parameters.iter().enumerate() {
// Codegen actual parameters // Codegen actual parameters
let arg_name = format!("arg.{}", p.name); let arg_name = format!("arg.{}", p_name);
let param = scope let param = scope
.block .block
.build_named(format!("{}.get", arg_name), Instr::Param(i)) .build_named(format!("{}.get", arg_name), Instr::Param(i))
.unwrap(); .unwrap();
let alloca = scope.allocate(&p.meta, &p.ty).unwrap(); let alloca = scope.allocate(&p_name, &p_ty).unwrap();
scope scope
.block .block
.build_named(format!("{}.store", arg_name), Instr::Store(alloca, param)) .build_named(format!("{}.store", arg_name), Instr::Store(alloca, param))
.unwrap(); .unwrap();
scope.stack_values.insert( scope.stack_values.insert(
p.name.clone(), p_name.clone(),
StackValue( StackValue(
StackValueKind::mutable(p.ty.is_mutable(), alloca), StackValueKind::mutable(p_ty.is_mutable(), alloca),
TypeKind::CodegenPtr(Box::new(p.ty.clone())), TypeKind::CodegenPtr(Box::new(p_ty.clone())),
), ),
); );
// Generate debug info
// if let (Some(debug_scope), Some(location)) = (
// &debug_scope,
// mir_function.signature().into_debug(tokens, compile_unit),
// ) {
// debug.metadata(
// &location,
// DebugMetadata::ParamVar(DebugParamVariable {
// name: p_name.clone(),
// arg_idx: i as u32,
// ty: p_ty.get_debug_type_hard(
// *debug_scope,
// &debug,
// &debug_types,
// &type_values,
// &types,
// self.module_id,
// &self.tokens,
// &modules,
// ),
// always_preserve: true,
// flags: DwarfFlags,
// }),
// );
// }
} }
let state = State::default(); let state = State::default();
if let Some(ret) = block.codegen(scope, &state, false)? { if let Some(ret) = block.codegen(scope, &state)? {
scope.block.terminate(Term::Ret(ret.instr())).unwrap(); scope.block.terminate(Term::Ret(ret.instr())).unwrap();
} else { } else {
if !scope.block.delete_if_unused().unwrap() { if !scope.block.delete_if_unused().unwrap() {
@ -709,20 +604,7 @@ impl mir::Block {
&self, &self,
mut scope: &mut Scope<'ctx, 'a>, mut scope: &mut Scope<'ctx, 'a>,
state: &State, state: &State,
create_debug_scope: bool,
) -> Result<Option<StackValue>, ErrorKind> { ) -> Result<Option<StackValue>, ErrorKind> {
let parent_scope = if let Some(debug) = &mut scope.debug {
let parent_scope = debug.scope.clone();
if create_debug_scope {
let location = self.meta.into_debug(scope.tokens, &debug.scope).unwrap();
let scope = debug.info.lexical_scope(&debug.scope, DebugLexicalScope { location });
debug.scope = scope;
}
Some(parent_scope)
} else {
None
};
for stmt in &self.statements { for stmt in &self.statements {
stmt.codegen(&mut scope, state)?.map(|s| { stmt.codegen(&mut scope, state)?.map(|s| {
if let Some(debug) = &scope.debug { if let Some(debug) = &scope.debug {
@ -733,7 +615,7 @@ impl mir::Block {
}); });
} }
let return_value = if let Some((kind, expr)) = &self.return_expression { if let Some((kind, expr)) = &self.return_expression {
if let Some(expr) = expr { if let Some(expr) = expr {
let ret = expr.codegen(&mut scope, &mut state.load(true))?; let ret = expr.codegen(&mut scope, &mut state.load(true))?;
match kind { match kind {
@ -756,13 +638,7 @@ impl mir::Block {
} }
} else { } else {
Ok(None) Ok(None)
};
if let Some(parent_scope) = parent_scope {
scope.debug.as_mut().unwrap().scope = parent_scope;
} }
return_value
} }
} }
@ -774,11 +650,11 @@ impl mir::Statement {
}); });
match &self.0 { match &self.0 {
mir::StmtKind::Let(NamedVariableRef(ty, name, meta), mutable, expression) => { mir::StmtKind::Let(NamedVariableRef(ty, name, _), mutable, expression) => {
let value = expression.codegen(scope, &state)?.unwrap(); let value = expression.codegen(scope, &state)?.unwrap();
let alloca = scope let alloca = scope
.allocate(meta, &value.1) .allocate(name, &value.1)
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location.clone()); .maybe_location(&mut scope.block, location.clone());
@ -866,7 +742,7 @@ impl mir::Statement {
let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap(); let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap();
let true_instr = condition_scope let true_instr = condition_scope
.block .block
.build(Instr::Constant(ConstValueKind::Bool(true))) .build(Instr::Constant(ConstValue::Bool(true)))
.unwrap(); .unwrap();
let check = condition_scope let check = condition_scope
.block .block
@ -883,7 +759,7 @@ impl mir::Statement {
.unwrap(); .unwrap();
let mut condition_true_scope = scope.with_block(condition_true_block); let mut condition_true_scope = scope.with_block(condition_true_block);
block.codegen(&mut condition_true_scope, state, true)?; block.codegen(&mut condition_true_scope, state)?;
condition_true_scope condition_true_scope
.block .block
@ -1057,7 +933,7 @@ impl mir::Expression {
scope.block.terminate(Term::Br(inner.value())).unwrap(); scope.block.terminate(Term::Br(inner.value())).unwrap();
let mut inner_scope = scope.with_block(inner); let mut inner_scope = scope.with_block(inner);
let ret = if let Some(ret) = block.codegen(&mut inner_scope, state, true)? { let ret = if let Some(ret) = block.codegen(&mut inner_scope, state)? {
Some(ret) Some(ret)
} else { } else {
None None
@ -1113,7 +989,7 @@ impl mir::Expression {
let first = scope let first = scope
.block .block
.build_named("array.zero", Instr::Constant(ConstValueKind::U32(0))) .build_named("array.zero", Instr::Constant(ConstValue::U32(0)))
.unwrap(); .unwrap();
( (
scope scope
@ -1167,10 +1043,8 @@ impl mir::Expression {
let load_n = format!("{}.load", array_name); let load_n = format!("{}.load", array_name);
let array = scope let array = scope
.allocate( .block
&self.1, .build_named(&array_name, Instr::Alloca(array_ty.clone()))
&TypeKind::Array(Box::new(elem_ty_kind.clone()), expressions.len() as u64),
)
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location.clone()); .maybe_location(&mut scope.block, location.clone());
@ -1180,11 +1054,11 @@ impl mir::Expression {
let index_expr = scope let index_expr = scope
.block .block
.build_named(index.to_string(), Instr::Constant(ConstValueKind::U32(index as u32))) .build_named(index.to_string(), Instr::Constant(ConstValue::U32(index as u32)))
.unwrap(); .unwrap();
let first = scope let first = scope
.block .block
.build_named("zero", Instr::Constant(ConstValueKind::U32(0))) .build_named("zero", Instr::Constant(ConstValue::U32(0)))
.unwrap(); .unwrap();
let ptr = scope let ptr = scope
.block .block
@ -1209,7 +1083,7 @@ impl mir::Expression {
TypeKind::Array(Box::new(elem_ty_kind), instr_list.len() as u64), TypeKind::Array(Box::new(elem_ty_kind), instr_list.len() as u64),
)) ))
} }
mir::ExprKind::Accessed(expression, type_kind, field, _) => { mir::ExprKind::Accessed(expression, type_kind, field) => {
let struct_val = expression.codegen(scope, &state.load(false))?.unwrap(); let struct_val = expression.codegen(scope, &state.load(false))?.unwrap();
let TypeKind::CodegenPtr(inner) = &struct_val.1 else { let TypeKind::CodegenPtr(inner) = &struct_val.1 else {
@ -1248,9 +1122,10 @@ impl mir::Expression {
)) ))
} }
} }
mir::ExprKind::Struct(key, items) => { mir::ExprKind::Struct(name, items) => {
let type_key = CustomTypeKey(name.clone(), scope.module_id);
let ty = Type::CustomType({ let ty = Type::CustomType({
let Some(a) = scope.type_values.get(&key) else { let Some(a) = scope.type_values.get(&type_key) else {
return Ok(None); return Ok(None);
}; };
*a *a
@ -1259,20 +1134,21 @@ impl mir::Expression {
let TypeDefinition { let TypeDefinition {
kind: TypeDefinitionKind::Struct(struct_ty), kind: TypeDefinitionKind::Struct(struct_ty),
.. ..
} = scope.types.get(scope.type_values.get(&key).unwrap()).unwrap(); } = scope.types.get(scope.type_values.get(&type_key).unwrap()).unwrap();
let indices = struct_ty.0.iter().enumerate(); let indices = struct_ty.0.iter().enumerate();
let load_n = format!("{}@{}.load", key.0, key.1); let load_n = format!("{}.load", name);
let struct_ptr = scope let struct_ptr = scope
.allocate(&self.1, &TypeKind::CustomType(key.clone())) .block
.build_named(name, Instr::Alloca(ty.clone()))
.unwrap() .unwrap()
.maybe_location(&mut scope.block, location.clone()); .maybe_location(&mut scope.block, location.clone());
for (field_n, exp, _) in items { for (field_n, exp) in items {
let gep_n = format!("{}@{}.{}.gep", key.0, key.1, field_n); let gep_n = format!("{}.{}.gep", name, field_n);
let store_n = format!("{}@{}.{}.store", key.0, key.1, field_n); let store_n = format!("{}.{}.store", name, field_n);
let i = indices.clone().find(|(_, f)| f.0 == *field_n).unwrap().0; let i = indices.clone().find(|(_, f)| f.0 == *field_n).unwrap().0;
let elem_ptr = scope let elem_ptr = scope
@ -1293,7 +1169,7 @@ impl mir::Expression {
Some(StackValue( Some(StackValue(
StackValueKind::Literal(struct_val), StackValueKind::Literal(struct_val),
TypeKind::CustomType(key.clone()), TypeKind::CustomType(type_key),
)) ))
} }
mir::ExprKind::Borrow(expr, mutable) => { mir::ExprKind::Borrow(expr, mutable) => {
@ -1359,45 +1235,24 @@ impl mir::Expression {
if val.1 == *type_kind { if val.1 == *type_kind {
Some(val) Some(val)
} else { } else {
let (ty, other) = if !state.should_load { match (&val.1, type_kind) {
let TypeKind::CodegenPtr(inner) = &val.1 else { (TypeKind::CodegenPtr(inner), TypeKind::UserPtr(_)) => match *inner.clone() {
panic!(); TypeKind::UserPtr(_) => Some(StackValue(
}; val.0.derive(
(*inner.clone(), TypeKind::CodegenPtr(Box::new(type_kind.clone()))) scope
} else { .block
(val.1.clone(), type_kind.clone()) .build(Instr::BitCast(
}; val.instr(),
Type::Ptr(Box::new(type_kind.get_type(scope.type_values))),
match (&ty, type_kind) { ))
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Some(StackValue( .unwrap(),
val.0.derive( ),
scope TypeKind::CodegenPtr(Box::new(type_kind.clone())),
.block )),
.build(Instr::BitCast(val.instr(), other.get_type(scope.type_values))) _ => panic!(),
.unwrap(), },
), (TypeKind::UserPtr(_), TypeKind::UserPtr(_))
other.clone(), | (TypeKind::Char, TypeKind::U8)
)),
(TypeKind::Borrow(ty1, _), TypeKind::UserPtr(ty2)) => {
if let TypeKind::Array(ty1, _) = ty1.as_ref() {
if ty1 == ty2 {
Some(StackValue(
val.0.derive(
scope
.block
.build(Instr::BitCast(val.instr(), other.get_type(scope.type_values)))
.unwrap(),
),
other,
))
} else {
return Err(ErrorKind::Null).unwrap();
}
} else {
return Err(ErrorKind::Null).unwrap();
}
}
(TypeKind::Char, TypeKind::U8)
| (TypeKind::U8, TypeKind::Char) | (TypeKind::U8, TypeKind::Char)
| (TypeKind::U8, TypeKind::I8) => Some(StackValue( | (TypeKind::U8, TypeKind::I8) => Some(StackValue(
val.0.derive( val.0.derive(
@ -1409,7 +1264,8 @@ impl mir::Expression {
type_kind.clone(), type_kind.clone(),
)), )),
_ => { _ => {
let cast_instr = ty let cast_instr = val
.1
.get_type(scope.type_values) .get_type(scope.type_values)
.cast_instruction(val.instr(), &type_kind.get_type(scope.type_values)) .cast_instruction(val.instr(), &type_kind.get_type(scope.type_values))
.unwrap(); .unwrap();
@ -1423,33 +1279,6 @@ impl mir::Expression {
} }
} }
mir::ExprKind::AssociatedFunctionCall(ty, call) => codegen_function_call(Some(ty), call, scope, state)?, mir::ExprKind::AssociatedFunctionCall(ty, call) => codegen_function_call(Some(ty), call, scope, state)?,
mir::ExprKind::GlobalRef(global_name, ty) => {
let global_value = scope.globals.get(global_name).unwrap();
let value = scope.block.build(Instr::GetGlobal(global_value.clone())).unwrap();
if !state.should_load {
let allocated = scope
.block
.build(Instr::Alloca(ty.get_type(scope.type_values)))
.unwrap();
scope
.block
.build(Instr::Store(allocated, value))
.unwrap()
.maybe_location(&mut scope.block, location.clone());
let a = Some(StackValue(
StackValueKind::Literal(allocated),
TypeKind::CodegenPtr(Box::new(ty.clone())),
));
a
} else {
let a = Some(StackValue(StackValueKind::Literal(value), ty.clone()));
a
}
}
}; };
if let Some(value) = &value { if let Some(value) = &value {
value.instr().maybe_location(&mut scope.block, location.clone()); value.instr().maybe_location(&mut scope.block, location.clone());
@ -1523,9 +1352,8 @@ fn codegen_function_call<'ctx, 'a>(
let ptr = if ret_type_kind != TypeKind::Void { let ptr = if ret_type_kind != TypeKind::Void {
let ptr = scope let ptr = scope
.allocator .block
.borrow_mut() .build_named(&call.name, Instr::Alloca(ret_type.clone()))
.allocate(&call.meta, &call.return_type)
.unwrap(); .unwrap();
scope scope
.block .block

View File

@ -1,27 +1,24 @@
use std::{cell::RefCell, collections::HashMap, mem, rc::Rc}; use std::{cell::RefCell, collections::HashMap, mem, rc::Rc};
use reid_lib::{ use reid_lib::{
builder::{FunctionValue, GlobalValue, InstructionValue, TypeValue}, builder::{InstructionValue, TypeValue},
debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue}, debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue},
intrinsics::LLVMIntrinsic,
Block, Context, Function, Instr, Module, Block, Context, Function, Instr, Module,
}; };
use crate::{ use crate::{
codegen::intrinsics::LLVMIntrinsicKind,
lexer::FullToken, lexer::FullToken,
mir::{ mir::{
self,
pass::{AssociatedFunctionKey, BinopKey}, pass::{AssociatedFunctionKey, BinopKey},
CustomTypeKey, FunctionParam, Metadata, SourceModuleId, TypeDefinition, TypeKind, CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind,
}, },
}; };
use super::{allocator::Allocator, ErrorKind, IntrinsicFunction}; use super::{allocator::Allocator, ErrorKind, IntrinsicFunction, ModuleCodegen};
pub struct Scope<'ctx, 'scope> { pub struct Scope<'ctx, 'scope> {
pub(super) context: &'ctx Context, pub(super) context: &'ctx Context,
pub(super) modules: &'scope HashMap<SourceModuleId, &'ctx mir::Module>, pub(super) modules: &'scope HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
pub(super) tokens: &'ctx Vec<FullToken>, pub(super) tokens: &'ctx Vec<FullToken>,
pub(super) module: &'ctx Module<'ctx>, pub(super) module: &'ctx Module<'ctx>,
pub(super) module_id: SourceModuleId, pub(super) module_id: SourceModuleId,
@ -29,15 +26,12 @@ pub struct Scope<'ctx, 'scope> {
pub(super) block: Block<'ctx>, pub(super) block: Block<'ctx>,
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>, pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>,
pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>, pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
pub(super) type_map: &'scope HashMap<CustomTypeKey, TypeDefinition>,
pub(super) assoc_functions: &'scope HashMap<AssociatedFunctionKey, ScopeFunctionKind<'ctx>>, pub(super) assoc_functions: &'scope HashMap<AssociatedFunctionKey, ScopeFunctionKind<'ctx>>,
pub(super) functions: &'scope HashMap<String, ScopeFunctionKind<'ctx>>, pub(super) functions: &'scope HashMap<String, ScopeFunctionKind<'ctx>>,
pub(super) binops: &'scope HashMap<BinopKey, StackBinopDefinition<'ctx>>, pub(super) binops: &'scope HashMap<BinopKey, StackBinopDefinition<'ctx>>,
pub(super) stack_values: HashMap<String, StackValue>, pub(super) stack_values: HashMap<String, StackValue>,
pub(super) globals: &'scope HashMap<String, GlobalValue>,
pub(super) debug: Option<Debug<'ctx>>, pub(super) debug: Option<Debug<'ctx>>,
pub(super) allocator: Rc<RefCell<Allocator>>, pub(super) allocator: Rc<RefCell<Allocator>>,
pub(super) llvm_intrinsics: Rc<RefCell<HashMap<LLVMIntrinsicKind, FunctionValue>>>,
} }
impl<'ctx, 'a> Scope<'ctx, 'a> { impl<'ctx, 'a> Scope<'ctx, 'a> {
@ -54,13 +48,10 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
functions: self.functions, functions: self.functions,
types: self.types, types: self.types,
type_values: self.type_values, type_values: self.type_values,
type_map: self.type_map,
stack_values: self.stack_values.clone(), stack_values: self.stack_values.clone(),
debug: self.debug.clone(), debug: self.debug.clone(),
allocator: self.allocator.clone(), allocator: self.allocator.clone(),
globals: self.globals,
binops: self.binops, binops: self.binops,
llvm_intrinsics: self.llvm_intrinsics.clone(),
} }
} }
@ -76,51 +67,8 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
self.type_values.get(key).and_then(|v| self.types.get(v)) self.type_values.get(key).and_then(|v| self.types.get(v))
} }
pub fn allocate(&self, meta: &Metadata, ty: &TypeKind) -> Option<InstructionValue> { pub fn allocate(&self, name: &String, ty: &TypeKind) -> Option<InstructionValue> {
self.allocator.borrow_mut().allocate(meta, ty) self.allocator.borrow_mut().allocate(name, ty)
}
pub fn get_intrinsic(&self, kind: LLVMIntrinsicKind) -> FunctionValue {
let mut intrinsics = self.llvm_intrinsics.borrow_mut();
if let Some(fun) = intrinsics.get(&kind) {
*fun
} else {
let intrinsic = self
.module
.intrinsic(match &kind {
LLVMIntrinsicKind::Max(ty) => LLVMIntrinsic::Max(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Min(ty) => LLVMIntrinsic::Min(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Abs(ty) => LLVMIntrinsic::Abs(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Memcpy(ty) => LLVMIntrinsic::Memcpy(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Sqrt(ty) => LLVMIntrinsic::Sqrt(ty.get_type(self.type_values)),
LLVMIntrinsicKind::PowI(lhs, rhs) => {
LLVMIntrinsic::PowI(lhs.get_type(self.type_values), rhs.get_type(self.type_values))
}
LLVMIntrinsicKind::Pow(ty) => LLVMIntrinsic::Pow(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Sin(ty) => LLVMIntrinsic::Sin(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Cos(ty) => LLVMIntrinsic::Cos(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Tan(ty) => LLVMIntrinsic::Tan(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ASin(ty) => LLVMIntrinsic::ASin(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ACos(ty) => LLVMIntrinsic::ACos(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ATan(ty) => LLVMIntrinsic::ATan(ty.get_type(self.type_values)),
LLVMIntrinsicKind::ATan2(ty) => LLVMIntrinsic::ATan2(ty.get_type(self.type_values)),
LLVMIntrinsicKind::SinH(ty) => LLVMIntrinsic::SinH(ty.get_type(self.type_values)),
LLVMIntrinsicKind::CosH(ty) => LLVMIntrinsic::CosH(ty.get_type(self.type_values)),
LLVMIntrinsicKind::TanH(ty) => LLVMIntrinsic::TanH(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Log(ty) => LLVMIntrinsic::Log(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Log2(ty) => LLVMIntrinsic::Log2(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Log10(ty) => LLVMIntrinsic::Log10(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Copysign(ty) => LLVMIntrinsic::Copysign(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Floor(ty) => LLVMIntrinsic::Floor(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Ceil(ty) => LLVMIntrinsic::Ceil(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Trunc(ty) => LLVMIntrinsic::Trunc(ty.get_type(self.type_values)),
LLVMIntrinsicKind::RoundEven(ty) => LLVMIntrinsic::RoundEven(ty.get_type(self.type_values)),
LLVMIntrinsicKind::Round(ty) => LLVMIntrinsic::Round(ty.get_type(self.type_values)),
})
.unwrap();
intrinsics.insert(kind, intrinsic.clone());
intrinsic
}
} }
} }
@ -181,7 +129,7 @@ impl StackValueKind {
} }
pub struct StackBinopDefinition<'ctx> { pub struct StackBinopDefinition<'ctx> {
pub(super) parameters: (FunctionParam, FunctionParam), pub(super) parameters: ((String, TypeKind), (String, TypeKind)),
pub(super) return_ty: TypeKind, pub(super) return_ty: TypeKind,
pub(super) kind: ScopeFunctionKind<'ctx>, pub(super) kind: ScopeFunctionKind<'ctx>,
} }
@ -199,14 +147,14 @@ impl<'ctx> StackBinopDefinition<'ctx> {
rhs: StackValue, rhs: StackValue,
scope: &mut Scope<'ctx, 'a>, scope: &mut Scope<'ctx, 'a>,
) -> Result<StackValue, ErrorKind> { ) -> Result<StackValue, ErrorKind> {
let (lhs, rhs) = if lhs.1 == self.parameters.0.ty && rhs.1 == self.parameters.1.ty { let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 {
(lhs, rhs) (lhs, rhs)
} else { } else {
(rhs, lhs) (rhs, lhs)
}; };
let name = format!( let name = format!(
"binop.{}.{}.{}.call", "binop.{}.{}.{}.call",
self.parameters.0.ty, self.parameters.1.ty, self.return_ty self.parameters.0 .1, self.parameters.1 .1, self.return_ty
); );
self.kind.codegen(&name, &[lhs, rhs], &self.return_ty, None, scope) self.kind.codegen(&name, &[lhs, rhs], &self.return_ty, None, scope)
} }

View File

@ -6,7 +6,7 @@ use reid_lib::{
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocation, DebugPointerType, DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocation, DebugPointerType,
DebugPosition, DebugScopeValue, DebugStructType, DebugTypeData, DebugTypeValue, DwarfEncoding, DwarfFlags, DebugPosition, DebugScopeValue, DebugStructType, DebugTypeData, DebugTypeValue, DwarfEncoding, DwarfFlags,
}, },
Block, CmpPredicate, ConstValueKind, Instr, Type, Block, CmpPredicate, ConstValue, Instr, Type,
}; };
use crate::{ use crate::{
@ -14,7 +14,10 @@ use crate::{
mir::{self, CustomTypeKey, Metadata, SourceModuleId, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral}, mir::{self, CustomTypeKey, Metadata, SourceModuleId, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral},
}; };
use super::scope::{Debug, Scope}; use super::{
scope::{Debug, Scope},
ModuleCodegen,
};
impl mir::CmpOperator { impl mir::CmpOperator {
pub(super) fn predicate(&self) -> CmpPredicate { pub(super) fn predicate(&self) -> CmpPredicate {
@ -31,36 +34,34 @@ impl mir::CmpOperator {
impl mir::Literal { impl mir::Literal {
pub(super) fn as_const(&self, block: &mut Block) -> InstructionValue { pub(super) fn as_const(&self, block: &mut Block) -> InstructionValue {
block block.build_named(format!("{}", self), self.as_const_kind()).unwrap()
.build_named(format!("{}", self), Instr::Constant(self.as_const_kind()))
.unwrap()
} }
pub(super) fn as_const_kind(&self) -> ConstValueKind { pub(super) fn as_const_kind(&self) -> Instr {
match self.clone() { Instr::Constant(match self.clone() {
mir::Literal::I8(val) => ConstValueKind::I8(val), mir::Literal::I8(val) => ConstValue::I8(val),
mir::Literal::I16(val) => ConstValueKind::I16(val), mir::Literal::I16(val) => ConstValue::I16(val),
mir::Literal::I32(val) => ConstValueKind::I32(val), mir::Literal::I32(val) => ConstValue::I32(val),
mir::Literal::I64(val) => ConstValueKind::I64(val), mir::Literal::I64(val) => ConstValue::I64(val),
mir::Literal::I128(val) => ConstValueKind::I128(val), mir::Literal::I128(val) => ConstValue::I128(val),
mir::Literal::U8(val) => ConstValueKind::U8(val), mir::Literal::U8(val) => ConstValue::U8(val),
mir::Literal::U16(val) => ConstValueKind::U16(val), mir::Literal::U16(val) => ConstValue::U16(val),
mir::Literal::U32(val) => ConstValueKind::U32(val), mir::Literal::U32(val) => ConstValue::U32(val),
mir::Literal::U64(val) => ConstValueKind::U64(val), mir::Literal::U64(val) => ConstValue::U64(val),
mir::Literal::U128(val) => ConstValueKind::U128(val), mir::Literal::U128(val) => ConstValue::U128(val),
mir::Literal::Bool(val) => ConstValueKind::Bool(val), mir::Literal::Bool(val) => ConstValue::Bool(val),
mir::Literal::String(val) => ConstValueKind::Str(val.clone()), mir::Literal::String(val) => ConstValue::Str(val.clone()),
mir::Literal::Vague(VagueLiteral::Number(val)) => ConstValueKind::I32(val as i32), mir::Literal::Vague(VagueLiteral::Number(val)) => ConstValue::I32(val as i32),
mir::Literal::Vague(VagueLiteral::Decimal(val)) => ConstValueKind::F32(val as f32), mir::Literal::Vague(VagueLiteral::Decimal(val)) => ConstValue::F32(val as f32),
mir::Literal::F16(val) => ConstValueKind::F16(val), mir::Literal::F16(val) => ConstValue::F16(val),
mir::Literal::F32B(val) => ConstValueKind::F32B(val), mir::Literal::F32B(val) => ConstValue::F32B(val),
mir::Literal::F32(val) => ConstValueKind::F32(val), mir::Literal::F32(val) => ConstValue::F32(val),
mir::Literal::F64(val) => ConstValueKind::F64(val), mir::Literal::F64(val) => ConstValue::F64(val),
mir::Literal::F80(val) => ConstValueKind::F80(val), mir::Literal::F80(val) => ConstValue::F80(val),
mir::Literal::F128(val) => ConstValueKind::F128(val), mir::Literal::F128(val) => ConstValue::F128(val),
mir::Literal::F128PPC(val) => ConstValueKind::F128PPC(val), mir::Literal::F128PPC(val) => ConstValue::F128PPC(val),
mir::Literal::Char(c) => ConstValueKind::U8(c as u8), mir::Literal::Char(c) => ConstValue::U8(c as u8),
} })
} }
} }
@ -79,7 +80,7 @@ impl TypeKind {
TypeKind::U128 => Type::U128, TypeKind::U128 => Type::U128,
TypeKind::Bool => Type::Bool, TypeKind::Bool => Type::Bool,
TypeKind::F16 => Type::F16, TypeKind::F16 => Type::F16,
TypeKind::F16B => Type::F32B, TypeKind::F32B => Type::F32B,
TypeKind::F32 => Type::F32, TypeKind::F32 => Type::F32,
TypeKind::F64 => Type::F64, TypeKind::F64 => Type::F64,
TypeKind::F128 => Type::F128, TypeKind::F128 => Type::F128,
@ -106,7 +107,8 @@ impl TypeKind {
&debug.scope, &debug.scope,
debug.info, debug.info,
debug.types, debug.types,
scope.type_map, scope.type_values,
scope.types,
scope.module_id, scope.module_id,
scope.tokens, scope.tokens,
scope.modules, scope.modules,
@ -118,10 +120,11 @@ impl TypeKind {
scope: &DebugScopeValue, scope: &DebugScopeValue,
debug_info: &DebugInformation, debug_info: &DebugInformation,
debug_types: &HashMap<TypeKind, DebugTypeValue>, debug_types: &HashMap<TypeKind, DebugTypeValue>,
type_map: &HashMap<CustomTypeKey, TypeDefinition>, type_values: &HashMap<CustomTypeKey, TypeValue>,
types: &HashMap<TypeValue, TypeDefinition>,
local_mod: SourceModuleId, local_mod: SourceModuleId,
tokens: &Vec<FullToken>, tokens: &Vec<FullToken>,
modules: &HashMap<SourceModuleId, &mir::Module>, modules: &HashMap<SourceModuleId, ModuleCodegen>,
) -> DebugTypeValue { ) -> DebugTypeValue {
if let Some(ty) = debug_types.get(self) { if let Some(ty) = debug_types.get(self) {
return *ty; return *ty;
@ -137,12 +140,13 @@ impl TypeKind {
scope, scope,
debug_info, debug_info,
debug_types, debug_types,
type_map, type_values,
types,
local_mod, local_mod,
tokens, tokens,
modules, modules,
), ),
size_bits: self.size_of(type_map), size_bits: self.size_of(),
}) })
} }
TypeKind::Array(elem_ty, len) => { TypeKind::Array(elem_ty, len) => {
@ -150,20 +154,21 @@ impl TypeKind {
scope, scope,
debug_info, debug_info,
debug_types, debug_types,
type_map, type_values,
types,
local_mod, local_mod,
tokens, tokens,
modules, modules,
); );
DebugTypeData::Array(DebugArrayType { DebugTypeData::Array(DebugArrayType {
size_bits: self.size_of(type_map), size_bits: self.size_of(),
align_bits: self.alignment(), align_bits: self.alignment(),
element_type: elem_ty, element_type: elem_ty,
length: *len, length: *len,
}) })
} }
TypeKind::CustomType(key) => { TypeKind::CustomType(key) => {
let typedef = type_map.get(key).unwrap(); let typedef = types.get(type_values.get(key).unwrap()).unwrap();
match &typedef.kind { match &typedef.kind {
TypeDefinitionKind::Struct(struct_type) => { TypeDefinitionKind::Struct(struct_type) => {
let mut fields = Vec::new(); let mut fields = Vec::new();
@ -179,20 +184,21 @@ impl TypeKind {
name: field.0.clone(), name: field.0.clone(),
scope: scope.clone(), scope: scope.clone(),
pos: location.map(|l| l.pos), pos: location.map(|l| l.pos),
size_bits: field.1.size_of(type_map), size_bits: field.1.size_of(),
offset: size_bits, offset: size_bits,
flags: DwarfFlags, flags: DwarfFlags,
ty: field.1.get_debug_type_hard( ty: field.1.get_debug_type_hard(
scope, scope,
debug_info, debug_info,
debug_types, debug_types,
type_map, type_values,
types,
local_mod, local_mod,
tokens, tokens,
modules, modules,
), ),
}); });
size_bits += field.1.size_of(type_map); size_bits += field.1.size_of();
} }
{ {
let location = if typedef.source_module != local_mod { let location = if typedef.source_module != local_mod {
@ -214,7 +220,7 @@ impl TypeKind {
} }
_ => DebugTypeData::Basic(DebugBasicType { _ => DebugTypeData::Basic(DebugBasicType {
name, name,
size_bits: self.size_of(type_map), size_bits: self.size_of(),
encoding: match self { encoding: match self {
TypeKind::Bool => DwarfEncoding::Boolean, TypeKind::Bool => DwarfEncoding::Boolean,
TypeKind::I8 => DwarfEncoding::SignedChar, TypeKind::I8 => DwarfEncoding::SignedChar,
@ -223,7 +229,7 @@ impl TypeKind {
TypeKind::U16 | TypeKind::U32 | TypeKind::U64 | TypeKind::U128 => DwarfEncoding::Unsigned, TypeKind::U16 | TypeKind::U32 | TypeKind::U64 | TypeKind::U128 => DwarfEncoding::Unsigned,
TypeKind::F16 TypeKind::F16
| TypeKind::F32 | TypeKind::F32
| TypeKind::F16B | TypeKind::F32B
| TypeKind::F64 | TypeKind::F64
| TypeKind::F80 | TypeKind::F80
| TypeKind::F128 | TypeKind::F128

View File

@ -1,14 +1,13 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::{Debug, Write}, fmt::{Debug, Write},
path::PathBuf,
}; };
use crate::{ use crate::{
ast::token_stream::{self, TokenRange}, ast::token_stream::{self, TokenRange},
codegen, codegen,
lexer::{self, Cursor, FullToken, Position}, lexer::{self, Cursor, FullToken, Position},
mir::{self, macros, pass, typecheck, Metadata, SourceModuleId}, mir::{self, pass, typecheck, Metadata, SourceModuleId},
}; };
use crate::mir::typecheck::ErrorKind as TypecheckError; use crate::mir::typecheck::ErrorKind as TypecheckError;
@ -34,8 +33,6 @@ pub enum ErrorKind {
TypeInferenceError(#[source] mir::pass::Error<TypecheckError>), TypeInferenceError(#[source] mir::pass::Error<TypecheckError>),
#[error("{}{}", label("(Linker) "), .0.kind)] #[error("{}{}", label("(Linker) "), .0.kind)]
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
#[error("{}{}", label("(Macro) "), .0)]
MacroError(#[from] mir::pass::Error<macros::ErrorKind>),
#[error("{}{}", label("(Codegen) "), .0)] #[error("{}{}", label("(Codegen) "), .0)]
CodegenError(#[from] codegen::ErrorKind), CodegenError(#[from] codegen::ErrorKind),
} }
@ -51,7 +48,7 @@ impl ErrorKind {
} }
impl ErrorKind { impl ErrorKind {
pub fn get_meta(&self) -> Metadata { fn get_meta(&self) -> Metadata {
match &self { match &self {
ErrorKind::LexerError(error) => error.metadata, ErrorKind::LexerError(error) => error.metadata,
ErrorKind::ParserError(error) => error.metadata, ErrorKind::ParserError(error) => error.metadata,
@ -61,19 +58,6 @@ impl ErrorKind {
ErrorKind::CodegenError(error) => match error { ErrorKind::CodegenError(error) => match error {
codegen::ErrorKind::Null => Default::default(), codegen::ErrorKind::Null => Default::default(),
}, },
ErrorKind::MacroError(error) => error.metadata,
}
}
pub fn get_type_str(&self) -> &str {
match self {
ErrorKind::LexerError(_) => "lexer",
ErrorKind::ParserError(_) => "parser",
ErrorKind::TypeCheckError(_) => "typechecker",
ErrorKind::TypeInferenceError(_) => "type-inferrer",
ErrorKind::LinkerError(_) => "linker",
ErrorKind::MacroError(_) => "macro-pass",
ErrorKind::CodegenError(_) => "codegen",
} }
} }
} }
@ -95,47 +79,22 @@ pub struct ErrorModule {
#[derive(Debug, Clone, PartialEq, Eq, Default)] #[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ErrorModules { pub struct ErrorModules {
pub(super) module_map: HashMap<mir::SourceModuleId, ErrorModule>, module_map: HashMap<mir::SourceModuleId, ErrorModule>,
pub(super) source_id_map: HashMap<PathBuf, mir::SourceModuleId>,
module_counter: mir::SourceModuleId, module_counter: mir::SourceModuleId,
} }
impl ErrorModules { impl ErrorModules {
pub fn add_module<T: Into<String>>( pub fn add_module<T: Into<String>>(&mut self, name: T) -> Option<mir::SourceModuleId> {
&mut self, let id = self.module_counter.increment();
name: T, self.module_map.insert(
path: Option<PathBuf>, id,
external_module_id: Option<SourceModuleId>, ErrorModule {
) -> Option<mir::SourceModuleId> { name: name.into(),
let module_id = path.as_ref().and_then(|p| self.source_id_map.get(p)); tokens: None,
source: None,
if let Some(module_id) = module_id { },
Some(*module_id) );
} else { Some(id)
let id = if let Some(module_id) = external_module_id {
self.module_counter = SourceModuleId(module_id.0.max(self.module_counter.0));
if let Some(_) = self.module_map.get(&module_id) {
panic!("Can not use external module id: Module already exists!")
}
module_id
} else {
self.module_counter.increment()
};
if let Some(path) = path {
self.source_id_map.insert(path, id);
}
self.module_map.insert(
id,
ErrorModule {
name: name.into(),
tokens: None,
source: None,
},
);
Some(id)
}
} }
pub fn set_tokens(&mut self, id: mir::SourceModuleId, tokens: Vec<FullToken>) { pub fn set_tokens(&mut self, id: mir::SourceModuleId, tokens: Vec<FullToken>) {
@ -158,7 +117,7 @@ impl ErrorModules {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct ReidError { pub struct ReidError {
map: ErrorModules, map: ErrorModules,
pub errors: Vec<ErrorKind>, errors: Vec<ErrorKind>,
} }
impl ReidError { impl ReidError {
@ -207,10 +166,6 @@ impl ReidError {
pub fn from_kind(errors: Vec<ErrorKind>, map: ErrorModules) -> ReidError { pub fn from_kind(errors: Vec<ErrorKind>, map: ErrorModules) -> ReidError {
ReidError { map, errors } ReidError { map, errors }
} }
pub fn extend(&mut self, other: ReidError) {
self.errors.extend(other.errors);
}
} }
impl std::error::Error for ReidError {} impl std::error::Error for ReidError {}
@ -227,7 +182,9 @@ impl std::fmt::Display for ReidError {
let module = self.map.module(&meta.source_module_id); let module = self.map.module(&meta.source_module_id);
let position = if let Some(module) = module { let position = if let Some(module) = module {
if let Some(tokens) = &module.tokens { if let Some(tokens) = &module.tokens {
meta.range.into_position(tokens).or(meta.position.map(|p| (p, p))) let range_tokens = meta.range.into_tokens(&tokens);
get_position(&range_tokens).or(meta.position.map(|p| (p, p)))
} else if let Some(position) = meta.position { } else if let Some(position) = meta.position {
Some((position, position)) Some((position, position))
} else { } else {
@ -277,11 +234,6 @@ impl TokenRange {
.take(self.end + 1 - self.start) .take(self.end + 1 - self.start)
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
pub fn into_position<'v>(&self, tokens: &'v Vec<FullToken>) -> Option<(Position, Position)> {
let tokens = self.into_tokens(tokens);
get_position(&tokens)
}
} }
fn get_position(tokens: &Vec<&FullToken>) -> Option<(Position, Position)> { fn get_position(tokens: &Vec<&FullToken>) -> Option<(Position, Position)> {

View File

@ -25,58 +25,38 @@ impl LDRunner {
let dyn_linker_path = find_objectfile(&self.dynamic_linker); let dyn_linker_path = find_objectfile(&self.dynamic_linker);
let crt1_path = find_objectfile("crt1.o"); let crt1_path = find_objectfile("crt1.o");
let crti_path = find_objectfile("crti.o");
let crtn_path = find_objectfile("crtn.o");
log::debug!("LDRunner: Using dynamic linker at: {:?}", dyn_linker_path); println!("LDRunner: Using dynamic linker at: {:?}", dyn_linker_path);
let mut ld = Command::new(&self.command); let mut ld = Command::new(&self.command);
ld.arg("-dynamic-linker") ld.arg("-dynamic-linker")
.arg(dyn_linker_path) .arg(dyn_linker_path)
.arg(crt1_path) .arg(crt1_path);
.arg(crti_path);
for library in &self.libraries { for library in &self.libraries {
ld.arg(format!("-l{}", library)); ld.arg(format!("-l{}", library));
} }
ld.arg(crtn_path);
ld.arg(input_path.to_str().unwrap()) ld.arg(input_path.to_str().unwrap())
.arg("-o") .arg("-o")
.arg(out_path.to_str().unwrap()); .arg(out_path.to_str().unwrap());
log::debug!("{:#?}", ld); println!(
log::debug!(
"LDRunner: Executing linker to objfile at {:?} => {:?}", "LDRunner: Executing linker to objfile at {:?} => {:?}",
input_path, input_path, out_path
out_path
); );
dbg!(&ld);
let ld_output = ld.output().expect("Unable to execute ld!"); ld.spawn().expect("Unable to execute ld!");
if !ld_output.status.success() {
let code = ld_output.status.code().unwrap_or(255);
log::error!("LD exited with code {code}");
println!("{}", unsafe { String::from_utf8_unchecked(ld_output.stderr) });
return;
}
thread::sleep(Duration::from_millis(100)); thread::sleep(Duration::from_millis(100));
log::debug!("Setting executable bit to {:?}..", out_path); println!("Setting executable bit to {:?}..", out_path);
Command::new("chmod")
let chmod_output = Command::new("chmod")
.arg("+x") .arg("+x")
.arg(out_path) .arg(out_path)
.output() .spawn()
.expect("Unable to execute ld!"); .unwrap();
if !chmod_output.status.success() {
let code = chmod_output.status.code().unwrap_or(255);
log::error!("chmod exited with code {code}");
println!("{}", unsafe { String::from_utf8_unchecked(chmod_output.stderr) });
return;
}
thread::sleep(Duration::from_millis(100)); thread::sleep(Duration::from_millis(100));
} }
} }
@ -86,12 +66,6 @@ fn find_objectfile(name: &str) -> String {
.arg(&name) .arg(&name)
.output() .output()
.expect("Unable to execute whereis"); .expect("Unable to execute whereis");
if !whereis.status.success() {
let code = whereis.status.code().unwrap_or(255);
log::error!("whereis exited with code {code}");
println!("{}", unsafe { String::from_utf8_unchecked(whereis.stderr) });
panic!();
}
let whereis_output = String::from_utf8(whereis.stdout).unwrap(); let whereis_output = String::from_utf8(whereis.stdout).unwrap();
whereis_output whereis_output
@ -104,15 +78,3 @@ fn find_objectfile(name: &str) -> String {
.unwrap() .unwrap()
.to_owned() .to_owned()
} }
pub fn execute(path: &PathBuf) -> Option<i32> {
let output = Command::new(path.clone()).output().expect("Unable to execute {path}");
if !output.status.success() {
let code = output.status.code().unwrap_or(255);
log::error!("{path:?} exited with code {code}");
println!("{}", unsafe { String::from_utf8_unchecked(output.stderr) });
}
output.status.code()
}

View File

@ -8,36 +8,22 @@
//! Much of the syntax in Reid is directly inspired by rust, but mostly it is //! Much of the syntax in Reid is directly inspired by rust, but mostly it is
//! driven by simplicity. //! driven by simplicity.
//! //!
//! Specifications and a bunch of [documentation for the language can be found
//! here](./documentation/).
//!
//! An example of a real whole program (a CPU pathtracer) can be found [in
//! examples/cpu_raytracer.reid](./examples/cpu_raytracer.reid), go have a look!
//!
//! Reid is currently able to (non-exhaustively): //! Reid is currently able to (non-exhaustively):
//! - Do basic algebra binary and unary-operations (e.g. Add, Sub, Div, Mult, //! - Do basic algebra (e.g. Add, Sub, Mult)
//! And, Not)
//! - Resolve complex one-liners correctly using PEDMAS (e.g. `5 + 2 * 5 - 5 * //! - Resolve complex one-liners correctly using PEDMAS (e.g. `5 + 2 * 5 - 5 *
//! 5` is calculated correctly) //! 5` is calculated correctly)
//! - Handle borrows/derefs, pointers.
//! - Declare and call functions with varying parameters and return types //! - Declare and call functions with varying parameters and return types
//! - Perform type-checking and type-inference such that return-types and //! - Perform type-checking and type-inference such that return-types and
//! parameter types must always match. //! parameter types must always match.
//! - Do simple logic-operations (e.g. If/And/Or) //! - Do simple logic-operations (e.g. If/And/Or)
//! - Handle, access, define and initialize structs and arrays.
//! - Define and execute For/While loops
//! - Output detailed debug information
//! - Define extern functions that can be linked to outside modules such as
//! `libc`.
//! - Define custom binary operations for any two types that hasn't been defined
//! previously (such as `u16 + u32`).
//! //!
//! //! An example program of Reid, that calculates the 5th fibonacci number (and
//! An example program of Reid, that calculates the 5th fibonacci number: //! uses Rust for highlighting) is:
//! ```reid //! ```reid
//! fn main() -> u16 { //! fn main() -> u16 {
//! return fibonacci(5); //! return fibonacci(5);
//! } //! }
//!
//! fn fibonacci(n: u16) -> u16 { //! fn fibonacci(n: u16) -> u16 {
//! if n <= 2 { //! if n <= 2 {
//! return 1; //! return 1;
@ -46,13 +32,16 @@
//! } //! }
//! ``` //! ```
//! //!
//! TODOs still (see README.md for more) //! Currently missing relevant features (TODOs) are:
//! - Error handling //! - ~~Arrays~~ (DONE)
//! - Lexing & parsing of whitespace and comments as well //! - Structs (and custom types as such)
//! - LSP implementation //! - ~~Extern functions~~ (DONE)
//! - ~~Strings~~ (DONE)
//! - Loops
//! - Debug Symbols
//! ``` //! ```
use std::{collections::HashMap, path::PathBuf}; use std::{path::PathBuf, thread, time::Duration};
use ast::{ use ast::{
lexer::{self, FullToken, Token}, lexer::{self, FullToken, Token},
@ -67,16 +56,10 @@ use mir::{
}; };
use reid_lib::{compile::CompileOutput, Context}; use reid_lib::{compile::CompileOutput, Context};
use crate::{ use crate::ast::TopLevelStatement;
ast::TopLevelStatement,
mir::{
macros::{form_macros, MacroModule, MacroPass},
SourceModuleId,
},
};
pub mod ast; mod ast;
pub mod codegen; mod codegen;
pub mod error_raporting; pub mod error_raporting;
pub mod ld; pub mod ld;
pub mod mir; pub mod mir;
@ -86,11 +69,9 @@ mod util;
pub fn parse_module<'map, T: Into<String>>( pub fn parse_module<'map, T: Into<String>>(
source: &str, source: &str,
name: T, name: T,
path: Option<PathBuf>,
map: &'map mut ErrorModules, map: &'map mut ErrorModules,
module_id: Option<SourceModuleId>,
) -> Result<(mir::SourceModuleId, Vec<FullToken>), ReidError> { ) -> Result<(mir::SourceModuleId, Vec<FullToken>), ReidError> {
let id = map.add_module(name.into(), path, module_id).unwrap(); let id = map.add_module(name.into()).unwrap();
map.set_source(id, source.to_owned()); map.set_source(id, source.to_owned());
let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?; let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?;
@ -98,7 +79,7 @@ pub fn parse_module<'map, T: Into<String>>(
map.set_tokens(id, tokens.clone()); map.set_tokens(id, tokens.clone());
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:#?}", &tokens); println!("{:#?}", &tokens);
Ok((id, tokens)) Ok((id, tokens))
} }
@ -109,7 +90,7 @@ pub fn compile_module<'map>(
map: &'map mut ErrorModules, map: &'map mut ErrorModules,
path: Option<PathBuf>, path: Option<PathBuf>,
is_main: bool, is_main: bool,
) -> Result<Result<mir::Module, (ast::Module, ReidError)>, ReidError> { ) -> Result<mir::Module, ReidError> {
let module = map.module(&module_id).cloned().unwrap(); let module = map.module(&module_id).cloned().unwrap();
let mut token_stream = TokenStream::from(&tokens); let mut token_stream = TokenStream::from(&tokens);
@ -121,8 +102,6 @@ pub fn compile_module<'map>(
statements.push(statement); statements.push(statement);
} }
let errors = token_stream.errors();
drop(token_stream); drop(token_stream);
let ast_module = ast::Module { let ast_module = ast::Module {
@ -133,33 +112,10 @@ pub fn compile_module<'map>(
is_main, is_main,
}; };
if errors.len() > 0 {
// dbg!(&ast_module);
return Ok(Err((
ast_module,
ReidError::from_kind(
errors
.into_iter()
.map(|e| {
error_raporting::ErrorKind::from(mir::pass::Error {
metadata: mir::Metadata {
source_module_id: module_id,
range: *e.get_range().unwrap_or(&Default::default()),
position: None,
},
kind: e,
})
})
.collect(),
map.clone(),
),
)));
}
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:#?}", &ast_module); dbg!(&ast_module);
Ok(Ok(ast_module.process(module_id))) Ok(ast_module.process(module_id))
} }
pub fn perform_all_passes<'map>( pub fn perform_all_passes<'map>(
@ -167,60 +123,7 @@ pub fn perform_all_passes<'map>(
module_map: &'map mut ErrorModules, module_map: &'map mut ErrorModules,
) -> Result<(), ReidError> { ) -> Result<(), ReidError> {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:#?}", &context); dbg!(&context);
#[cfg(debug_assertions)]
log::trace!("{:#}", &context);
let state = context.pass(&mut LinkerPass {
module_map,
is_lib: true,
})?;
for module in &mut context.modules {
for intrinsic in form_intrinsics() {
module.1.functions.insert(0, intrinsic);
}
}
#[cfg(debug_assertions)]
log::trace!("{:-^100}", "LINKER OUTPUT");
#[cfg(debug_assertions)]
log::trace!("{:#}", &context);
#[cfg(debug_assertions)]
log::trace!("{:#?}", &state);
if !state.errors.is_empty() {
return Err(ReidError::from_kind(
state.errors.iter().map(|e| e.clone().into()).collect(),
module_map.clone(),
));
}
let mut macro_modules: HashMap<_, MacroModule> = HashMap::new();
for (k, v) in &context.modules {
macro_modules.insert(k.clone(), v.into());
}
let mut macro_pass = MacroPass {
macros: form_macros(),
module_map: macro_modules,
};
let state = context.pass(&mut macro_pass)?;
#[cfg(debug_assertions)]
log::trace!("{:-^100}", "MACRO OUTPUT");
#[cfg(debug_assertions)]
log::trace!("{:#}", &context);
#[cfg(debug_assertions)]
log::trace!("{:#?}", &state);
if !state.errors.is_empty() {
return Err(ReidError::from_kind(
state.errors.iter().map(|e| e.clone().into()).collect(),
module_map.clone(),
));
}
let mut binops = BinopMap::default(); let mut binops = BinopMap::default();
for module in &mut context.modules { for module in &mut context.modules {
@ -228,11 +131,11 @@ pub fn perform_all_passes<'map>(
binops binops
.set( .set(
mir::pass::BinopKey { mir::pass::BinopKey {
params: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()), params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
operator: intrinsic.op, operator: intrinsic.op,
}, },
mir::pass::ScopeBinopDef { mir::pass::ScopeBinopDef {
hands: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()), hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
operator: intrinsic.op, operator: intrinsic.op,
return_ty: intrinsic.return_type.clone(), return_ty: intrinsic.return_type.clone(),
}, },
@ -242,18 +145,46 @@ pub fn perform_all_passes<'map>(
} }
} }
for module in &mut context.modules {
for intrinsic in form_intrinsics() {
module.1.functions.insert(0, intrinsic);
}
}
#[cfg(debug_assertions)]
println!("{:#}", &context);
let state = context.pass(&mut LinkerPass {
module_map,
is_lib: true,
})?;
#[cfg(debug_assertions)]
println!("{:-^100}", "LINKER OUTPUT");
#[cfg(debug_assertions)]
println!("{:#}", &context);
#[cfg(debug_assertions)]
dbg!(&state);
if !state.errors.is_empty() {
return Err(ReidError::from_kind(
state.errors.iter().map(|e| e.clone().into()).collect(),
module_map.clone(),
));
}
let mut refs = TypeRefs::with_binops(binops); let mut refs = TypeRefs::with_binops(binops);
let state = context.pass(&mut TypeInference { refs: &mut refs })?; let state = context.pass(&mut TypeInference { refs: &mut refs })?;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:-^70}", "TYPE INFERRER OUTPUT"); println!("{:-^100}", "TYPE INFERRER OUTPUT");
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{}", &refs); println!("{}", &refs);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:#}", &context); println!("{:#}", &context);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:#?}", &state); dbg!(&state);
if !state.errors.is_empty() { if !state.errors.is_empty() {
return Err(ReidError::from_kind( return Err(ReidError::from_kind(
@ -269,11 +200,11 @@ pub fn perform_all_passes<'map>(
let state = context.pass(&mut TypeCheck { refs: &refs })?; let state = context.pass(&mut TypeCheck { refs: &refs })?;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:-^100}", "TYPECHECKER OUTPUT"); println!("{:-^100}", "TYPECHECKER OUTPUT");
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:#}", &context); println!("{:#}", &context);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:#?}", &state); dbg!(&state);
if !state.errors.is_empty() { if !state.errors.is_empty() {
return Err(ReidError::from_kind( return Err(ReidError::from_kind(
@ -302,17 +233,17 @@ pub fn compile_and_pass<'map>(
let path = path.canonicalize().unwrap(); let path = path.canonicalize().unwrap();
let name = path.file_name().unwrap().to_str().unwrap().to_owned(); let name = path.file_name().unwrap().to_str().unwrap().to_owned();
let (id, tokens) = parse_module(source, name, Some(path.clone()), module_map, None)?; let (id, tokens) = parse_module(source, name, module_map)?;
let module = compile_module(id, tokens, module_map, Some(path.clone()), true)?.map_err(|(_, e)| e)?; let module = compile_module(id, tokens, module_map, Some(path.clone()), true)?;
let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned()); let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned());
perform_all_passes(&mut mir_context, module_map)?; perform_all_passes(&mut mir_context, module_map)?;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:-^100}", "FINAL OUTPUT"); println!("{:-^100}", "FINAL OUTPUT");
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{:#}", &mir_context); println!("{:#}", &mir_context);
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION"))); let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
let codegen_modules = match mir_context.codegen(&mut context) { let codegen_modules = match mir_context.codegen(&mut context) {
@ -321,7 +252,7 @@ pub fn compile_and_pass<'map>(
}; };
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
log::trace!("{}", &codegen_modules.context); println!("{}", &codegen_modules.context);
let compiled = codegen_modules.compile(cpu, features); let compiled = codegen_modules.compile(cpu, features);
Ok(( Ok((

View File

@ -1,149 +0,0 @@
use std::{fs, path::PathBuf, process};
use argh::FromArgs;
use log::*;
use reid::{
compile_simple,
ld::{execute, LDRunner},
CustomIRs,
};
use reid_lib::compile::CompileOutput;
#[derive(FromArgs, PartialEq, Debug)]
/// Compile or run a Reid (.reid) file
#[argh(help_triggers("-h", "--help", "help"))]
struct Options {
#[argh(option, short = 'l', default = "log::Level::Info")]
/// log level
log_level: log::Level,
#[argh(switch, short = 't')]
/// should logs be timestamped
timestamps: bool,
#[argh(subcommand)]
command: Command,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum Command {
Build(BuildOpts),
Run(RunOpts),
}
#[derive(FromArgs, PartialEq, Debug)]
/// Build an executable file without running it
#[argh(subcommand, name = "build")]
struct BuildOpts {
#[argh(option, long = "lib", short = 'l')]
/// additional libraries to link against (with ld)
libraries: Vec<String>,
#[argh(positional)]
path: PathBuf,
}
#[derive(FromArgs, PartialEq, Debug)]
/// Build and then execute the executable
#[argh(subcommand, name = "run")]
struct RunOpts {
#[argh(option, long = "lib", short = 'l')]
/// additional libraries to link against (with ld)
libraries: Vec<String>,
#[argh(positional)]
path: PathBuf,
}
fn main() {
let options: Options = argh::from_env();
let mut errlog = stderrlog::new();
errlog.module(module_path!()).verbosity(options.log_level);
if options.timestamps {
errlog.timestamp(stderrlog::Timestamp::Second);
}
errlog.init().unwrap();
match &options.command {
Command::Build(BuildOpts { libraries, path }) | Command::Run(RunOpts { libraries, path }) => {
let cpu = std::env::var("CPU").unwrap_or("generic".to_owned());
let features = std::env::var("REIDFLAGS").unwrap_or("".to_owned());
let path = match path.canonicalize() {
Ok(path) => path,
Err(e) => {
error!("{e}");
return;
}
};
let parent = path.with_extension("");
let llvm_ir_path = parent.with_extension("ll");
let object_path = parent.with_extension("o");
let llir_path = parent.with_extension("llir");
let mir_path = parent.with_extension("mir");
let asm_path = parent.with_extension("asm");
let out_path = object_path.with_extension("out");
let before = std::time::SystemTime::now();
let text = match fs::read_to_string(&path) {
Ok(text) => text,
Err(e) => {
error!("Could not read file: {e}");
return;
}
};
match compile_simple(&text, PathBuf::from(&path), Some(cpu), vec![features]) {
Ok((
CompileOutput {
triple: _triple,
assembly,
obj_buffer,
llvm_ir: _llvm_ir,
},
CustomIRs { llir, mir },
)) => {
log::trace!("{}", _llvm_ir);
log::debug!("Compiled with triple: {}\n", &_triple);
log::debug!("Output LLVM IR to {:?}", llvm_ir_path);
log::debug!("Output Assembly to {:?}", asm_path);
log::debug!("Output Object-file to {:?}\n", object_path);
log::debug!("Output LLIR-file to {:?}\n", llir_path);
log::debug!("Output MIR-file to {:?}\n", mir_path);
fs::write(&llvm_ir_path, &_llvm_ir).expect("Could not write LLVM IR -file!");
fs::write(&asm_path, &assembly).expect("Could not write Assembly-file!");
fs::write(&object_path, &obj_buffer).expect("Could not write Object-file!");
fs::write(&llir_path, &llir).expect("Could not write LLIR-file!");
fs::write(&mir_path, &mir).expect("Could not write MIR-file!");
let after = std::time::SystemTime::now();
log::info!(
"Compilation took: {:.2}ms\n",
(after.duration_since(before).unwrap().as_micros() as f32) / 1000.
);
log::info!("Linking {:?}", &object_path);
let linker = std::env::var("LD").unwrap_or("ld".to_owned());
let mut linker = LDRunner::from_command(&linker).with_library("c").with_library("m");
for library in libraries {
linker = linker.with_library(&library);
}
linker.invoke(&object_path, &out_path);
}
Err(e) => {
log::error!("{e}");
return;
}
};
match &options.command {
Command::Build(_) => {}
Command::Run(_) => {
if let Some(code) = execute(&out_path) {
process::exit(code);
}
}
}
}
}
}

View File

@ -49,9 +49,6 @@ impl Display for Module {
for typedef in &self.typedefs { for typedef in &self.typedefs {
writeln!(inner_f, "{}", typedef)?; writeln!(inner_f, "{}", typedef)?;
} }
for global in &self.globals {
writeln!(inner_f, "global {} = {}", global.name, global.kind)?;
}
for (ty, fun) in &self.associated_functions { for (ty, fun) in &self.associated_functions {
writeln!(inner_f, "(Assoc {}) {}", ty, fun)?; writeln!(inner_f, "(Assoc {}) {}", ty, fun)?;
} }
@ -62,33 +59,9 @@ impl Display for Module {
} }
} }
impl Display for GlobalKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GlobalKind::Literal(literal) => Display::fmt(literal, f),
GlobalKind::Array(global_kinds) => {
f.write_char('[')?;
let mut iter = global_kinds.iter();
if let Some(global) = iter.next() {
Display::fmt(global, f)?;
while let Some(global) = iter.next() {
write!(f, ", ")?;
Display::fmt(global, f)?;
}
}
f.write_char(']')
}
}
}
}
impl Display for Import { impl Display for Import {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!( write!(f, "import {}", self.0.join("::"))
f,
"import {}",
self.0.iter().map(|(s, _)| s.clone()).collect::<Vec<_>>().join("::")
)
} }
} }
@ -98,11 +71,11 @@ impl Display for BinopDefinition {
f, f,
"{}impl binop ({}: {:#}) {} ({}: {:#}) -> {:#} ", "{}impl binop ({}: {:#}) {} ({}: {:#}) -> {:#} ",
if self.exported { "exported " } else { "" }, if self.exported { "exported " } else { "" },
self.lhs.name, self.lhs.0,
self.lhs.ty, self.lhs.1,
self.op, self.op,
self.rhs.name, self.rhs.0,
self.rhs.ty, self.rhs.1,
self.return_type self.return_type
)?; )?;
Display::fmt(&self.fn_kind, f) Display::fmt(&self.fn_kind, f)
@ -117,7 +90,7 @@ impl Display for TypeDefinition {
self.name, self.name,
self.source_module, self.source_module,
if let Some(mod_id) = self.importer { if let Some(mod_id) = self.importer {
format!("; imported by {}", mod_id) format!("; imported to {}", mod_id)
} else { } else {
String::new() String::new()
} }
@ -152,9 +125,6 @@ impl Display for StructField {
impl Display for FunctionDefinition { impl Display for FunctionDefinition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(documentation) = &self.documentation {
writeln!(f, "/// {}", documentation)?;
}
write!( write!(
f, f,
"{}fn {}({}) -> {:#} ", "{}fn {}({}) -> {:#} ",
@ -162,7 +132,7 @@ impl Display for FunctionDefinition {
self.name, self.name,
self.parameters self.parameters
.iter() .iter()
.map(|FunctionParam { name, ty, .. }| format!("{}: {:#}", name, ty)) .map(|(n, t)| format!("{}: {:#}", n, t))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "), .join(", "),
self.return_type self.return_type
@ -279,16 +249,16 @@ impl Display for ExprKind {
} }
f.write_char(']') f.write_char(']')
} }
ExprKind::Struct(key, items) => { ExprKind::Struct(name, items) => {
write!(f, "{:?} ", key)?; write!(f, "{} ", name)?;
f.write_char('{')?; f.write_char('{')?;
let mut state = Default::default(); let mut state = Default::default();
let mut inner_f = PadAdapter::wrap(f, &mut state); let mut inner_f = PadAdapter::wrap(f, &mut state);
let mut iter = items.iter(); let mut iter = items.iter();
if let Some((name, expr, _)) = iter.next() { if let Some((name, expr)) = iter.next() {
write!(inner_f, "\n{}: {}", name, expr)?; write!(inner_f, "\n{}: {}", name, expr)?;
while let Some((name, expr, _)) = iter.next() { while let Some((name, expr)) = iter.next() {
writeln!(inner_f, ",")?; writeln!(inner_f, ",")?;
write!(inner_f, "{}: {}", name, expr)?; write!(inner_f, "{}: {}", name, expr)?;
} }
@ -296,7 +266,7 @@ impl Display for ExprKind {
} }
f.write_char('}') f.write_char('}')
} }
ExprKind::Accessed(expression, type_kind, name, _) => { ExprKind::Accessed(expression, type_kind, name) => {
Display::fmt(&expression, f)?; Display::fmt(&expression, f)?;
write_access(f, name)?; write_access(f, name)?;
write!(f, "<{}>", type_kind) write!(f, "<{}>", type_kind)
@ -310,7 +280,6 @@ impl Display for ExprKind {
write!(f, "::")?; write!(f, "::")?;
Display::fmt(function_call, f) Display::fmt(function_call, f)
} }
ExprKind::GlobalRef(global_value, type_kind) => write!(f, "global<{}>(${})", type_kind, global_value),
} }
} }
} }
@ -471,7 +440,7 @@ impl Display for TypeKind {
} }
TypeKind::Vague(vague_type) => Display::fmt(vague_type, f), TypeKind::Vague(vague_type) => Display::fmt(vague_type, f),
TypeKind::F16 => write!(f, "f16"), TypeKind::F16 => write!(f, "f16"),
TypeKind::F16B => write!(f, "f16b"), TypeKind::F32B => write!(f, "f16b"),
TypeKind::F32 => write!(f, "f32"), TypeKind::F32 => write!(f, "f32"),
TypeKind::F64 => write!(f, "f64"), TypeKind::F64 => write!(f, "f64"),
TypeKind::F128 => write!(f, "f128"), TypeKind::F128 => write!(f, "f128"),

View File

@ -48,7 +48,7 @@ impl TypeKind {
TypeKind::Borrow(..) => false, TypeKind::Borrow(..) => false,
TypeKind::UserPtr(..) => false, TypeKind::UserPtr(..) => false,
TypeKind::F16 => true, TypeKind::F16 => true,
TypeKind::F16B => true, TypeKind::F32B => true,
TypeKind::F32 => true, TypeKind::F32 => true,
TypeKind::F64 => true, TypeKind::F64 => true,
TypeKind::F128 => true, TypeKind::F128 => true,
@ -57,7 +57,7 @@ impl TypeKind {
} }
} }
pub fn size_of(&self, map: &HashMap<CustomTypeKey, TypeDefinition>) -> u64 { pub fn size_of(&self) -> u64 {
match self { match self {
TypeKind::Bool => 1, TypeKind::Bool => 1,
TypeKind::I8 => 8, TypeKind::I8 => 8,
@ -72,27 +72,14 @@ impl TypeKind {
TypeKind::U128 => 128, TypeKind::U128 => 128,
TypeKind::Void => 0, TypeKind::Void => 0,
TypeKind::Char => 8, TypeKind::Char => 8,
TypeKind::Array(type_kind, len) => type_kind.size_of(map) * (*len as u64), TypeKind::Array(type_kind, len) => type_kind.size_of() * (*len as u64),
TypeKind::CustomType(key) => match &map.get(key) { TypeKind::CustomType(..) => 32,
Some(def) => match &def.kind {
TypeDefinitionKind::Struct(struct_type) => {
let mut size = 0;
for field in &struct_type.0 {
size += field.1.size_of(map)
}
size
}
},
// Easy to recognize default number. Used e.g. when sorting
// types by size
None => 404,
},
TypeKind::CodegenPtr(_) => 64, TypeKind::CodegenPtr(_) => 64,
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"), TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
TypeKind::Borrow(..) => 64, TypeKind::Borrow(..) => 64,
TypeKind::UserPtr(_) => 64, TypeKind::UserPtr(_) => 64,
TypeKind::F16 => 16, TypeKind::F16 => 16,
TypeKind::F16B => 16, TypeKind::F32B => 16,
TypeKind::F32 => 32, TypeKind::F32 => 32,
TypeKind::F64 => 64, TypeKind::F64 => 64,
TypeKind::F128 => 128, TypeKind::F128 => 128,
@ -123,7 +110,7 @@ impl TypeKind {
TypeKind::Borrow(_, _) => 64, TypeKind::Borrow(_, _) => 64,
TypeKind::UserPtr(_) => 64, TypeKind::UserPtr(_) => 64,
TypeKind::F16 => 16, TypeKind::F16 => 16,
TypeKind::F16B => 16, TypeKind::F32B => 16,
TypeKind::F32 => 32, TypeKind::F32 => 32,
TypeKind::F64 => 64, TypeKind::F64 => 64,
TypeKind::F128 => 128, TypeKind::F128 => 128,
@ -153,7 +140,7 @@ impl TypeKind {
| TypeKind::U128 | TypeKind::U128
| TypeKind::Char => TypeCategory::Integer, | TypeKind::Char => TypeCategory::Integer,
TypeKind::F16 TypeKind::F16
| TypeKind::F16B | TypeKind::F32B
| TypeKind::F32 | TypeKind::F32
| TypeKind::F64 | TypeKind::F64
| TypeKind::F128 | TypeKind::F128
@ -202,36 +189,6 @@ impl TypeKind {
} }
} }
impl Ord for TypeKind {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
use std::cmp::*;
let category_ord = self.category().partial_cmp(&other.category());
match category_ord {
Some(Ordering::Equal) | None => {
if !self.signed() && other.signed() {
return Ordering::Less;
}
if self.signed() && !other.signed() {
return Ordering::Greater;
}
let self_size = self.size_of(&HashMap::new());
let other_size = other.size_of(&HashMap::new());
if self_size == 32 && other_size != 32 {
return Ordering::Less;
} else if self_size != 32 && other_size == 32 {
return Ordering::Greater;
}
self_size.cmp(&self_size)
}
Some(ord) => ord,
}
}
}
impl BinaryOperator { impl BinaryOperator {
pub fn is_commutative(&self) -> bool { pub fn is_commutative(&self) -> bool {
match self { match self {
@ -259,28 +216,7 @@ impl BinaryOperator {
} }
} }
const TYPE_CATEGORY_ORDER: [TypeCategory; 5] = [ #[derive(PartialEq, Eq, PartialOrd, Ord)]
TypeCategory::Integer,
TypeCategory::Bool,
TypeCategory::Real,
TypeCategory::Other,
TypeCategory::TypeRef,
];
impl PartialOrd for TypeCategory {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
use std::cmp::*;
let self_idx = TYPE_CATEGORY_ORDER.iter().enumerate().find(|s| s.1 == self);
let other_idx = TYPE_CATEGORY_ORDER.iter().enumerate().find(|s| s.1 == other);
if let (Some(self_idx), Some(other_idx)) = (self_idx, other_idx) {
Some(self_idx.cmp(&other_idx))
} else {
None
}
}
}
#[derive(PartialEq, Eq, Ord)]
pub enum TypeCategory { pub enum TypeCategory {
Integer, Integer,
Real, Real,
@ -469,8 +405,11 @@ impl Expression {
TypeKind::Array(Box::new(first.1), expressions.len() as u64), TypeKind::Array(Box::new(first.1), expressions.len() as u64),
)) ))
} }
Accessed(_, type_kind, ..) => Ok((ReturnKind::Soft, type_kind.clone())), Accessed(_, type_kind, _) => Ok((ReturnKind::Soft, type_kind.clone())),
Struct(key, _) => Ok((ReturnKind::Soft, TypeKind::CustomType(key.clone()))), Struct(name, _) => Ok((
ReturnKind::Soft,
TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)),
)),
Borrow(expr, mutable) => { Borrow(expr, mutable) => {
let ret_type = expr.return_type(refs, mod_id)?; let ret_type = expr.return_type(refs, mod_id)?;
Ok((ret_type.0, TypeKind::Borrow(Box::new(ret_type.1), *mutable))) Ok((ret_type.0, TypeKind::Borrow(Box::new(ret_type.1), *mutable)))
@ -490,7 +429,6 @@ impl Expression {
Err(_) => Ok((ReturnKind::Soft, type_kind.clone())), Err(_) => Ok((ReturnKind::Soft, type_kind.clone())),
}, },
AssociatedFunctionCall(_, fcall) => fcall.return_type(), AssociatedFunctionCall(_, fcall) => fcall.return_type(),
GlobalRef(_, type_kind) => Ok((ReturnKind::Soft, type_kind.clone())),
} }
} }
@ -498,7 +436,7 @@ impl Expression {
match &self.0 { match &self.0 {
ExprKind::Variable(var_ref) => Some(var_ref), ExprKind::Variable(var_ref) => Some(var_ref),
ExprKind::Indexed(lhs, _, _) => lhs.backing_var(), ExprKind::Indexed(lhs, _, _) => lhs.backing_var(),
ExprKind::Accessed(lhs, ..) => lhs.backing_var(), ExprKind::Accessed(lhs, _, _) => lhs.backing_var(),
ExprKind::Borrow(expr, _) => expr.backing_var(), ExprKind::Borrow(expr, _) => expr.backing_var(),
ExprKind::Deref(expr) => expr.backing_var(), ExprKind::Deref(expr) => expr.backing_var(),
ExprKind::Block(block) => block.backing_var(), ExprKind::Block(block) => block.backing_var(),
@ -510,7 +448,6 @@ impl Expression {
ExprKind::If(_) => None, ExprKind::If(_) => None,
ExprKind::CastTo(expression, _) => expression.backing_var(), ExprKind::CastTo(expression, _) => expression.backing_var(),
ExprKind::AssociatedFunctionCall(..) => None, ExprKind::AssociatedFunctionCall(..) => None,
ExprKind::GlobalRef(..) => None,
} }
} }
@ -556,7 +493,6 @@ impl Expression {
ExprKind::Deref(_) => None, ExprKind::Deref(_) => None,
ExprKind::CastTo(expression, _) => expression.num_value()?, ExprKind::CastTo(expression, _) => expression.num_value()?,
ExprKind::AssociatedFunctionCall(..) => None, ExprKind::AssociatedFunctionCall(..) => None,
ExprKind::GlobalRef(..) => None,
}) })
} }
} }

View File

@ -11,8 +11,8 @@ use crate::{
compile_module, compile_module,
error_raporting::{ErrorModules, ReidError}, error_raporting::{ErrorModules, ReidError},
mir::{ mir::{
pass::BinopKey, BinopDefinition, CustomTypeKey, FunctionDefinitionKind, SourceModuleId, StructType, pass::BinopKey, BinopDefinition, CustomTypeKey, FunctionDefinitionKind, SourceModuleId, TypeDefinition,
TypeDefinition, TypeDefinitionKind, TypeKind, TypeKind,
}, },
parse_module, parse_module,
}; };
@ -46,19 +46,13 @@ pub enum ErrorKind {
NoMainDefined, NoMainDefined,
#[error("Main module has no main-function!")] #[error("Main module has no main-function!")]
NoMainFunction, NoMainFunction,
#[error("Type {0} has cyclical fields!")]
CyclicalType(String),
#[error("Type {0} is imported cyclically!")]
RecursiveTypeImport(String),
#[error("Type {} does not exist in module {}", 0.0, 0.1)]
NoSuchTypeInModule(CustomTypeKey),
#[error("Function {1} in module {0} is private!")] #[error("Function {1} in module {0} is private!")]
FunctionIsPrivate(String, String), FunctionIsPrivate(String, String),
} }
pub fn compile_std(module_map: &mut ErrorModules) -> Result<Module, ReidError> { pub fn compile_std(module_map: &mut ErrorModules) -> Result<Module, ReidError> {
let (id, tokens) = parse_module(STD_SOURCE, STD_NAME, None, module_map, None)?; let (id, tokens) = parse_module(STD_SOURCE, STD_NAME, module_map)?;
let module = compile_module(id, tokens, module_map, None, false)?.map_err(|(_, e)| e)?; let module = compile_module(id, tokens, module_map, None, false)?;
let module_id = module.module_id; let module_id = module.module_id;
let mut mir_context = super::Context::from(vec![module], Default::default()); let mut mir_context = super::Context::from(vec![module], Default::default());
@ -76,21 +70,11 @@ pub struct LinkerPass<'map> {
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct LinkerState { pub struct LinkerState {
foreign_types: HashMap<SourceModuleId, HashMap<CustomTypeKey, SourceModuleId>>, extern_imported_types: HashMap<SourceModuleId, HashMap<String, SourceModuleId>>,
} }
type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, LinkerState, ErrorKind>; type LinkerPassState<'st, 'sc> = PassState<'st, 'sc, LinkerState, ErrorKind>;
#[derive(Clone, Debug)]
struct LinkerModule {
module: Rc<RefCell<Module>>,
// Functions imported directly from a module
function_imports: HashMap<String, (SourceModuleId, Metadata)>,
// Types imported either directly by the user or indirectly via functions.
// May contain type-imports that are again recursively imported elsewhere.
type_imports: HashMap<String, (SourceModuleId, Metadata)>,
}
impl<'map> Pass for LinkerPass<'map> { impl<'map> Pass for LinkerPass<'map> {
type Data = LinkerState; type Data = LinkerState;
type TError = ErrorKind; type TError = ErrorKind;
@ -118,56 +102,37 @@ impl<'map> Pass for LinkerPass<'map> {
} }
}; };
let mut modules = HashMap::<SourceModuleId, LinkerModule>::new(); let mut modules = HashMap::<SourceModuleId, Rc<RefCell<_>>>::new();
let mut module_ids = HashMap::<String, SourceModuleId>::new(); let mut module_ids = HashMap::<String, SourceModuleId>::new();
for (mod_id, module) in context.modules.drain() { for (mod_id, module) in context.modules.drain() {
modules.insert( modules.insert(mod_id, Rc::new(RefCell::new(module)));
mod_id,
LinkerModule {
module: Rc::new(RefCell::new(module)),
function_imports: HashMap::new(),
type_imports: HashMap::new(),
},
);
} }
let mut module_queue: Vec<LinkerModule> = modules.values().cloned().collect(); let mut modules_to_process: Vec<Rc<RefCell<_>>> = modules.values().cloned().collect();
while let Some(mut importer) = module_queue.pop() { let mut already_imported_types = HashSet::<CustomTypeKey>::new();
let importer_mod = importer.module.borrow_mut(); let mut already_imported_binops = HashSet::<BinopKey>::new();
// Gp go through all imports in this specific modulee while let Some(module) = modules_to_process.pop() {
for import in importer_mod.imports.clone() { let mut extern_types = HashMap::new();
let mut importer_module = module.borrow_mut();
for import in importer_module.imports.clone() {
let Import(path, _) = &import; let Import(path, _) = &import;
if path.len() != 2 { if path.len() != 2 {
state.ok::<_, Infallible>(Err(ErrorKind::InnerModulesNotYetSupported(import.clone())), import.1); state.ok::<_, Infallible>(Err(ErrorKind::InnerModulesNotYetSupported(import.clone())), import.1);
} }
// Cut the import statement into parts let module_name = unsafe { path.get_unchecked(0) };
let Some((module_name, _)) = path.get(0) else {
continue;
};
let Some((import_name, _)) = path.get(1) else {
continue;
};
// Actually compile or fetch the imported module let mut imported = if let Some(mod_id) = module_ids.get(module_name) {
let imported = if let Some(mod_id) = module_ids.get(module_name) {
modules.get(mod_id).unwrap() modules.get(mod_id).unwrap()
} else if module_name == STD_NAME { } else if module_name == STD_NAME {
let std = compile_std(&mut self.module_map)?; let std = compile_std(&mut self.module_map)?;
let module_id = std.module_id; modules.insert(std.module_id, Rc::new(RefCell::new(compile_std(&mut self.module_map)?)));
modules.insert( module_ids.insert(std.name, std.module_id);
std.module_id, modules.get(&std.module_id).unwrap()
LinkerModule {
module: Rc::new(RefCell::new(std)),
function_imports: HashMap::new(),
type_imports: HashMap::new(),
},
);
module_ids.insert(module_name.clone(), module_id);
modules.get(&module_id).unwrap()
} else { } else {
let file_path = PathBuf::from(&context.base.clone()).join(module_name.to_owned() + ".reid"); let file_path = PathBuf::from(&context.base.clone()).join(module_name.to_owned() + ".reid");
@ -176,13 +141,7 @@ impl<'map> Pass for LinkerPass<'map> {
continue; continue;
}; };
let (id, tokens) = match parse_module( let (id, tokens) = match parse_module(&source, module_name.clone(), &mut self.module_map) {
&source,
module_name.clone(),
Some(file_path.clone()),
&mut self.module_map,
None,
) {
Ok(val) => val, Ok(val) => val,
Err(err) => { Err(err) => {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
@ -197,40 +156,21 @@ impl<'map> Pass for LinkerPass<'map> {
}; };
match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) { match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) {
Ok(res) => match res { Ok(imported_module) => {
Ok(imported_module) => { if imported_module.is_main {
if imported_module.is_main {
state.ok::<_, Infallible>(
Err(ErrorKind::TriedLinkingMain(module_name.clone())),
import.1,
);
continue;
}
let module_id = imported_module.module_id;
module_ids.insert(imported_module.name.clone(), imported_module.module_id);
modules.insert(
module_id,
LinkerModule {
module: Rc::new(RefCell::new(imported_module)),
function_imports: HashMap::new(),
type_imports: HashMap::new(),
},
);
let imported = modules.get_mut(&module_id).unwrap();
module_queue.push(imported.clone());
imported
}
Err((_, err)) => {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
Err(ErrorKind::ModuleCompilationError( Err(ErrorKind::TriedLinkingMain(module_name.clone())),
module_name.clone(),
format!("{}", err),
)),
import.1, import.1,
); );
continue; continue;
} }
}, let module_id = imported_module.module_id;
module_ids.insert(imported_module.name.clone(), imported_module.module_id);
modules.insert(module_id, Rc::new(RefCell::new(imported_module)));
let imported = modules.get_mut(&module_id).unwrap();
modules_to_process.push(imported.clone());
imported
}
Err(err) => { Err(err) => {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
Err(ErrorKind::ModuleCompilationError( Err(ErrorKind::ModuleCompilationError(
@ -242,157 +182,70 @@ impl<'map> Pass for LinkerPass<'map> {
continue; continue;
} }
} }
};
let imported_module = imported.module.borrow();
if let Some(func) = imported_module.functions.iter().find(|f| f.name == *import_name) {
// If the imported item is a function, add it to the list of imported functions
importer
.function_imports
.insert(func.name.clone(), (imported_module.module_id, import.1));
} else if let Some(ty) = imported_module.typedefs.iter().find(|t| t.name == *import_name) {
// If the imported item is a type, add it to the list of imported types
// imported_types.insert((CustomTypeKey(ty.name.clone(), ty.source_module), true));
importer
.type_imports
.insert(ty.name.clone(), (imported_module.module_id, import.1));
} }
} .borrow_mut();
let module_id = importer_mod.module_id; let import_name = unsafe { path.get_unchecked(1) };
drop(importer_mod);
modules.insert(module_id, importer);
}
for (_, linker_module) in &modules { let mut imported_types = Vec::new();
let mut importer_module = linker_module.module.borrow_mut();
let mut unresolved_types = HashMap::new(); if let Some(func) = imported.functions.iter_mut().find(|f| f.name == *import_name) {
let func_name = func.name.clone();
// 1. Import functions and find all types that are dependencies of if !func.is_pub {
// functions
for (name, (function_source, import_meta)) in &linker_module.function_imports {
let mut function_module = modules.get(&function_source).unwrap().module.borrow_mut();
let func_module_name = function_module.name.clone();
let func_module_id = function_module.module_id;
let function = function_module.functions.iter_mut().find(|f| f.name == *name).unwrap();
// If function is not pub, error
if !function.is_pub {
state.ok::<_, Infallible>(
Err(ErrorKind::FunctionIsPrivate(func_module_name, function.name.clone())),
import_meta.clone(),
);
continue;
}
// If function already exists, error
if let Some(existing) = importer_module.functions.iter().find(|f| f.name == *name) {
if let Err(e) = existing.equals_as_imported(&function) {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
Err(ErrorKind::FunctionImportIssue(func_module_name, name.clone(), e)), Err(ErrorKind::FunctionIsPrivate(module_name.clone(), func_name.clone())),
import_meta.clone(), import.1,
); );
}
}
function.is_imported = true;
for ty in import_type(&function.return_type) {
unresolved_types.insert(ty, (import_meta.clone(), true));
}
for param in &function.parameters {
for ty in import_type(&param.ty) {
unresolved_types.insert(ty, (import_meta.clone(), true));
}
}
importer_module.functions.push(FunctionDefinition {
name: function.name.clone(),
documentation: function.documentation.clone(),
linkage_name: None,
is_pub: false,
is_imported: false,
return_type: function.return_type.clone(),
parameters: function.parameters.clone(),
kind: super::FunctionDefinitionKind::Extern(true),
source: Some(func_module_id),
signature_meta: function.signature(),
});
}
// 2. Add all manually imported types to the list of types that need
// to be resolved and recursed
for (name, (source_module, meta)) in &linker_module.type_imports {
let imported_ty_key = CustomTypeKey(name.clone(), source_module.clone());
let imported_ty = TypeKind::CustomType(imported_ty_key.clone());
let imported = modules.get(&imported_ty_key.1).unwrap().module.borrow();
for (ty, func) in &imported.associated_functions {
if *ty != imported_ty {
continue; continue;
} }
for ty in import_type(&func.return_type) { func.is_imported = true;
if unresolved_types.contains_key(&ty) {
continue; if let Some(existing) = importer_module.functions.iter().find(|f| f.name == *func_name) {
} if let Err(e) = existing.equals_as_imported(func) {
unresolved_types.insert(ty, (meta.clone(), true)); state.ok::<_, Infallible>(
} Err(ErrorKind::FunctionImportIssue(
for param in &func.parameters { module_name.clone(),
for ty in import_type(&param.ty) { func_name.clone(),
if unresolved_types.contains_key(&ty) { e,
continue; )),
} import.1,
unresolved_types.insert(ty, (meta.clone(), true)); );
} }
} }
}
unresolved_types.insert(imported_ty_key.clone(), (meta.clone(), false)); let types = import_type(&func.return_type, false);
} let return_type = func.return_type.clone();
imported_types.extend(types);
// 3. Recurse these types to find their true sources, find their let mut param_tys = Vec::new();
// dependencies, and list them all. Store manually imported types for (param_name, param_ty) in &func.parameters {
// in a separate mapping for later. let types = import_type(&param_ty, false);
let mut imported_types = HashMap::new(); imported_types.extend(types);
let mut foreign_keys = HashSet::new(); param_tys.push((param_name.clone(), param_ty.clone()));
}
let mut already_imported_binops = HashSet::new(); importer_module.functions.push(FunctionDefinition {
name: func_name.clone(),
linkage_name: None,
is_pub: false,
is_imported: false,
return_type,
parameters: param_tys,
kind: super::FunctionDefinitionKind::Extern(true),
});
} else if let Some(ty) = imported.typedefs.iter_mut().find(|f| f.name == *import_name) {
let external_key = CustomTypeKey(ty.name.clone(), ty.source_module);
let imported_ty = TypeKind::CustomType(external_key.clone());
imported_types.push((external_key, true));
for (ty, (meta, is_dependency)) in unresolved_types {
// First deal with manually imported types
if !is_dependency {
// Add them to the list of foreign types (types that are
// later replaced in-source by name)
let imported_ty_key = match resolve_type(&ty, &modules) {
Ok(ty) => {
foreign_keys.insert(CustomTypeKey(ty.0.clone(), importer_module.module_id));
ty
}
Err(e) => {
state.note_errors(&vec![e], meta);
return Ok(());
}
};
imported_types.insert(CustomTypeKey(ty.0.clone(), importer_module.module_id), ty.1);
let mut imported = modules.get(&imported_ty_key.1).unwrap().module.borrow_mut();
let imported_module_name = imported.name.clone();
let imported_module_id = imported.module_id.clone();
let imported_ty = TypeKind::CustomType(imported_ty_key);
// Add all binary operators that are defined for this type
for binop in &mut imported.binop_defs { for binop in &mut imported.binop_defs {
if binop.lhs.ty != imported_ty && binop.rhs.ty != imported_ty { if binop.lhs.1 != imported_ty && binop.rhs.1 != imported_ty {
continue; continue;
} }
let binop_key = BinopKey { let binop_key = BinopKey {
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()), params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
operator: binop.op, operator: binop.op,
}; };
if already_imported_binops.contains(&binop_key) { if already_imported_binops.contains(&binop_key) {
@ -417,7 +270,6 @@ impl<'map> Pass for LinkerPass<'map> {
} }
} }
// Import all functions that are associated with this type
for (ty, func) in &mut imported.associated_functions { for (ty, func) in &mut imported.associated_functions {
if *ty != imported_ty { if *ty != imported_ty {
continue; continue;
@ -427,11 +279,8 @@ impl<'map> Pass for LinkerPass<'map> {
if !func.is_pub { if !func.is_pub {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
Err(ErrorKind::FunctionIsPrivate( Err(ErrorKind::FunctionIsPrivate(module_name.clone(), func_name.clone())),
imported_module_name.clone(), import.1,
func_name.clone(),
)),
meta.clone(),
); );
continue; continue;
} }
@ -446,81 +295,115 @@ impl<'map> Pass for LinkerPass<'map> {
if let Err(e) = existing.equals_as_imported(func) { if let Err(e) = existing.equals_as_imported(func) {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
Err(ErrorKind::FunctionImportIssue( Err(ErrorKind::FunctionImportIssue(
imported_module_name.clone(), module_name.clone(),
func_name.clone(), func_name.clone(),
e, e,
)), )),
meta.clone(), import.1,
); );
} }
} }
let types = import_type(&func.return_type, false);
let return_type = func.return_type.clone();
imported_types.extend(types);
let mut param_tys = Vec::new();
for (param_name, param_ty) in &func.parameters {
let types = import_type(&param_ty, false);
imported_types.extend(types);
param_tys.push((param_name.clone(), param_ty.clone()));
}
importer_module.associated_functions.push(( importer_module.associated_functions.push((
ty.clone(), ty.clone(),
FunctionDefinition { FunctionDefinition {
name: func_name.clone(), name: func_name.clone(),
documentation: func.documentation.clone(),
linkage_name: Some(format!("{}::{}", ty, func_name)), linkage_name: Some(format!("{}::{}", ty, func_name)),
is_pub: false, is_pub: false,
is_imported: false, is_imported: false,
return_type: func.return_type.clone(), return_type,
parameters: func.parameters.clone(), parameters: param_tys,
kind: super::FunctionDefinitionKind::Extern(true), kind: super::FunctionDefinitionKind::Extern(true),
source: Some(imported_module_id),
signature_meta: func.signature_meta,
}, },
)); ));
} }
}
match resolve_types_recursively(&TypeKind::CustomType(ty.clone()), &modules, HashSet::new()) {
Ok(resolved) => {
imported_types.extend(resolved);
}
Err(e) => {
state.note_errors(&vec![e], meta);
return Ok(());
}
}
}
let mut typedef_keys = HashMap::new();
// 4. Import all listed types.
for (importer_typekey, imported_module_id) in &imported_types {
let importee_typekey = CustomTypeKey(importer_typekey.0.clone(), *imported_module_id);
if let Some(module_id) = typedef_keys.get(&importee_typekey) {
if *module_id != importer_module.module_id {
typedef_keys.insert(importee_typekey.clone(), importer_typekey.1);
}
} else { } else {
typedef_keys.insert(importee_typekey.clone(), importer_typekey.1); state.ok::<_, Infallible>(
Err(ErrorKind::ImportDoesNotExist(module_name.clone(), import_name.clone())),
import.1,
);
continue;
} }
}
for (typedef_key, importer_module_id) in &typedef_keys { let mut seen = HashSet::new();
let imported_ty_module = modules.get(&typedef_key.1).unwrap().module.borrow(); let mut current_extern_types = HashSet::new();
if let Some(typedef) = imported_ty_module seen.extend(imported_types.clone().iter().map(|t| t.0.clone()));
.typedefs current_extern_types.extend(imported_types.clone().iter().filter(|t| t.1).map(|t| t.0.clone()));
.iter() for extern_type in &current_extern_types {
.find(|ty| CustomTypeKey(ty.name.clone(), ty.source_module) == *typedef_key) extern_types.insert(extern_type.0.clone(), extern_type.1);
}
let imported_mod_id = imported.module_id;
let imported_mod_typedefs = &mut imported.typedefs;
for typekey in imported_types.clone() {
let typedef = imported_mod_typedefs
.iter()
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey.0)
.unwrap();
let inner = find_inner_types(typedef, seen.clone(), imported_mod_id);
seen.extend(inner.iter().cloned());
}
// TODO: Unable to import same-named type from multiple places..
let seen = seen
.difference(&already_imported_types)
.cloned() .cloned()
{ .collect::<HashSet<_>>();
importer_module.typedefs.push(TypeDefinition {
importer: Some(*importer_module_id), already_imported_types.extend(seen.clone());
..typedef
}); for typekey in &already_imported_types {
if current_extern_types.contains(typekey) {
let module_id = importer_module.module_id;
let typedef = importer_module
.typedefs
.iter_mut()
.find(|t| t.name == typekey.0 && t.source_module == typekey.1);
if let Some(typedef) = typedef {
typedef.importer = Some(module_id);
}
}
}
for typekey in seen.into_iter() {
let mut typedef = imported_mod_typedefs
.iter()
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey)
.unwrap()
.clone();
if current_extern_types.contains(&typekey) {
typedef = TypeDefinition {
importer: Some(importer_module.module_id),
..typedef
};
}
importer_module.typedefs.push(typedef);
} }
} }
state state
.scope .scope
.data .data
.foreign_types .extern_imported_types
.insert(importer_module.module_id, imported_types); .insert(importer_module.module_id, extern_types);
} }
let mut modules: Vec<Module> = modules let mut modules: Vec<Module> = modules
.into_values() .into_values()
.map(|v| Rc::into_inner(v.module).unwrap().into_inner()) .map(|v| Rc::into_inner(v).unwrap().into_inner())
.collect(); .collect();
for module in modules.drain(..) { for module in modules.drain(..) {
@ -530,33 +413,19 @@ impl<'map> Pass for LinkerPass<'map> {
Ok(()) Ok(())
} }
fn module(&mut self, module: &mut Module, state: PassState<Self::Data, Self::TError>) -> PassResult {
let foreign_types = &state.scope.data.foreign_types.get(&module.module_id);
if let Some(foreign_types) = foreign_types {
for ty in &mut module.typedefs {
match &mut ty.kind {
TypeDefinitionKind::Struct(StructType(fields)) => {
for field in fields {
field.1 = field.1.update_imported(foreign_types);
}
}
}
}
}
Ok(())
}
fn function( fn function(
&mut self, &mut self,
function: &mut FunctionDefinition, function: &mut FunctionDefinition,
state: PassState<Self::Data, Self::TError>, state: PassState<Self::Data, Self::TError>,
) -> PassResult { ) -> PassResult {
let mod_id = state.scope.module_id.unwrap(); if matches!(function.kind, FunctionDefinitionKind::Local(_, _)) {
let foreign_types = &state.scope.data.foreign_types.get(&mod_id); let mod_id = state.scope.module_id.unwrap();
if let Some(foreign_types) = foreign_types { let extern_types = &state.scope.data.extern_imported_types.get(&mod_id);
function.return_type = function.return_type.update_imported(*foreign_types); if let Some(extern_types) = extern_types {
for param in function.parameters.iter_mut() { function.return_type = function.return_type.update_imported(*extern_types, mod_id);
param.ty = param.ty.update_imported(foreign_types); for param in function.parameters.iter_mut() {
param.1 = param.1.update_imported(extern_types, mod_id);
}
} }
} }
Ok(()) Ok(())
@ -564,11 +433,11 @@ impl<'map> Pass for LinkerPass<'map> {
fn stmt(&mut self, stmt: &mut super::Statement, state: PassState<Self::Data, Self::TError>) -> PassResult { fn stmt(&mut self, stmt: &mut super::Statement, state: PassState<Self::Data, Self::TError>) -> PassResult {
let mod_id = state.scope.module_id.unwrap(); let mod_id = state.scope.module_id.unwrap();
let foreign_types = &state.scope.data.foreign_types.get(&mod_id); let extern_types = &state.scope.data.extern_imported_types.get(&mod_id);
if let Some(foreign_types) = foreign_types { if let Some(extern_types) = extern_types {
match &mut stmt.0 { match &mut stmt.0 {
super::StmtKind::Let(var_ref, _, _) => { super::StmtKind::Let(var_ref, _, _) => {
var_ref.0 = var_ref.0.update_imported(foreign_types); var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
} }
_ => {} _ => {}
} }
@ -578,29 +447,25 @@ impl<'map> Pass for LinkerPass<'map> {
fn expr(&mut self, expr: &mut super::Expression, state: PassState<Self::Data, Self::TError>) -> PassResult { fn expr(&mut self, expr: &mut super::Expression, state: PassState<Self::Data, Self::TError>) -> PassResult {
let mod_id = state.scope.module_id.unwrap(); let mod_id = state.scope.module_id.unwrap();
let foreign_types = &state.scope.data.foreign_types.get(&mod_id); let extern_types = &state.scope.data.extern_imported_types.get(&mod_id);
if let Some(foreign_types) = foreign_types { if let Some(extern_types) = extern_types {
match &mut expr.0 { match &mut expr.0 {
super::ExprKind::Variable(var_ref) => { super::ExprKind::Variable(var_ref) => {
var_ref.0 = var_ref.0.update_imported(foreign_types); var_ref.0 = var_ref.0.update_imported(extern_types, mod_id);
} }
super::ExprKind::Indexed(.., type_kind, _) => *type_kind = type_kind.update_imported(foreign_types), super::ExprKind::Indexed(.., type_kind, _) => {
super::ExprKind::Accessed(.., type_kind, _, _) => *type_kind = type_kind.update_imported(foreign_types), *type_kind = type_kind.update_imported(extern_types, mod_id)
super::ExprKind::BinOp(.., type_kind) => *type_kind = type_kind.update_imported(foreign_types), }
super::ExprKind::Accessed(.., type_kind, _) => {
*type_kind = type_kind.update_imported(extern_types, mod_id)
}
super::ExprKind::BinOp(.., type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id),
super::ExprKind::Borrow(..) => {} super::ExprKind::Borrow(..) => {}
super::ExprKind::Deref(..) => {} super::ExprKind::Deref(..) => {}
super::ExprKind::CastTo(_, type_kind) => *type_kind = type_kind.update_imported(foreign_types), super::ExprKind::CastTo(_, type_kind) => *type_kind = type_kind.update_imported(extern_types, mod_id),
super::ExprKind::AssociatedFunctionCall(type_kind, fn_call) => { super::ExprKind::AssociatedFunctionCall(type_kind, _) => {
*type_kind = type_kind.update_imported(foreign_types); *type_kind = type_kind.update_imported(extern_types, mod_id)
fn_call.return_type = fn_call.return_type.update_imported(foreign_types);
}
super::ExprKind::Struct(key, _) => {
*key = if let Some(mod_id) = foreign_types.get(&key) {
CustomTypeKey(key.0.clone(), *mod_id)
} else {
key.clone()
}
} }
_ => {} _ => {}
} }
@ -610,103 +475,78 @@ impl<'map> Pass for LinkerPass<'map> {
} }
impl TypeKind { impl TypeKind {
fn update_imported(&self, foreign_types: &HashMap<CustomTypeKey, SourceModuleId>) -> TypeKind { fn update_imported(
&self,
extern_types: &HashMap<String, SourceModuleId>,
importer_mod_id: SourceModuleId,
) -> TypeKind {
match &self { match &self {
TypeKind::Array(type_kind, len) => { TypeKind::Array(type_kind, len) => {
TypeKind::Array(Box::new(type_kind.update_imported(foreign_types)), *len) TypeKind::Array(Box::new(type_kind.update_imported(extern_types, importer_mod_id)), *len)
} }
TypeKind::CustomType(custom_type_key) => { TypeKind::CustomType(custom_type_key) => {
if let Some(mod_id) = foreign_types.get(&custom_type_key) { if let Some(mod_id) = extern_types.get(&custom_type_key.0) {
TypeKind::CustomType(CustomTypeKey(custom_type_key.0.clone(), *mod_id)) TypeKind::CustomType(CustomTypeKey(custom_type_key.0.clone(), *mod_id))
} else { } else {
self.clone() self.clone()
} }
} }
TypeKind::Borrow(type_kind, mutable) => { TypeKind::Borrow(type_kind, mutable) => TypeKind::Borrow(
TypeKind::Borrow(Box::new(type_kind.update_imported(foreign_types)), *mutable) Box::new(type_kind.update_imported(extern_types, importer_mod_id)),
*mutable,
),
TypeKind::UserPtr(type_kind) => {
TypeKind::UserPtr(Box::new(type_kind.update_imported(extern_types, importer_mod_id)))
}
TypeKind::CodegenPtr(type_kind) => {
TypeKind::CodegenPtr(Box::new(type_kind.update_imported(extern_types, importer_mod_id)))
} }
TypeKind::UserPtr(type_kind) => TypeKind::UserPtr(Box::new(type_kind.update_imported(foreign_types))),
TypeKind::CodegenPtr(type_kind) => TypeKind::CodegenPtr(Box::new(type_kind.update_imported(foreign_types))),
_ => self.clone(), _ => self.clone(),
} }
} }
} }
fn import_type(ty: &TypeKind) -> Vec<CustomTypeKey> { fn import_type(ty: &TypeKind, usable_import: bool) -> Vec<(CustomTypeKey, bool)> {
let mut imported_types = Vec::new(); let mut imported_types = Vec::new();
match &ty { match &ty {
TypeKind::CustomType(key) => imported_types.push(key.clone()), TypeKind::CustomType(key) => imported_types.push((key.clone(), usable_import)),
TypeKind::Borrow(ty, _) => imported_types.extend(import_type(ty)), TypeKind::Borrow(ty, _) => imported_types.extend(import_type(ty, usable_import)),
TypeKind::Array(ty, _) => imported_types.extend(import_type(ty)), TypeKind::Array(ty, _) => imported_types.extend(import_type(ty, usable_import)),
TypeKind::UserPtr(ty) => imported_types.extend(import_type(ty)), TypeKind::UserPtr(ty) => imported_types.extend(import_type(ty, usable_import)),
TypeKind::CodegenPtr(ty) => imported_types.extend(import_type(ty)), TypeKind::CodegenPtr(ty) => imported_types.extend(import_type(ty, usable_import)),
_ => {} _ => {}
}; };
imported_types imported_types
} }
fn resolve_type( fn find_inner_types(
ty: &CustomTypeKey, typedef: &TypeDefinition,
modules: &HashMap<SourceModuleId, LinkerModule>,
) -> Result<CustomTypeKey, ErrorKind> {
let mut source_module_id = ty.1;
let mut seen = HashSet::new();
loop {
seen.insert(source_module_id);
let source_module = modules.get(&source_module_id).unwrap();
if let Some((new_module_id, _)) = source_module.type_imports.get(&ty.0) {
if seen.contains(new_module_id) {
return Err(ErrorKind::RecursiveTypeImport(ty.0.clone()));
}
source_module_id = *new_module_id;
} else {
break;
}
}
Ok(CustomTypeKey(ty.0.clone(), source_module_id))
}
fn resolve_types_recursively(
ty: &TypeKind,
modules: &HashMap<SourceModuleId, LinkerModule>,
mut seen: HashSet<CustomTypeKey>, mut seen: HashSet<CustomTypeKey>,
) -> Result<HashMap<CustomTypeKey, SourceModuleId>, ErrorKind> { mod_id: SourceModuleId,
let mut types = HashMap::new(); ) -> Vec<CustomTypeKey> {
match ty { match &typedef.kind {
TypeKind::CustomType(type_key) => { crate::mir::TypeDefinitionKind::Struct(struct_type) => {
let resolved_ty = resolve_type(type_key, modules)?; let typenames = struct_type
.0
if seen.contains(&resolved_ty) {
return Err(ErrorKind::CyclicalType(type_key.0.clone()));
}
types.insert(type_key.clone(), resolved_ty.1);
seen.insert(resolved_ty.clone());
let resolved = modules
.get(&resolved_ty.1)
.unwrap()
.module
.borrow()
.typedefs
.iter() .iter()
.find(|t| t.name == resolved_ty.0) .filter(|t| matches!(t.1, TypeKind::CustomType(..)))
.ok_or(ErrorKind::NoSuchTypeInModule(type_key.clone())) .map(|t| match &t.1 {
.cloned()?; TypeKind::CustomType(CustomTypeKey(t, _)) => t,
match resolved.kind { _ => panic!(),
TypeDefinitionKind::Struct(StructType(fields)) => { })
for field in fields { .cloned()
types.extend(resolve_types_recursively(&field.1, modules, seen.clone())?); .collect::<Vec<_>>();
}
for typename in typenames {
if seen.contains(&CustomTypeKey(typename.clone(), mod_id)) {
continue;
} }
let inner = find_inner_types(typedef, seen.clone(), mod_id);
seen.insert(CustomTypeKey(typename, mod_id));
seen.extend(inner);
} }
seen.into_iter().collect()
} }
TypeKind::Array(type_kind, _) => types.extend(resolve_types_recursively(&type_kind, modules, seen.clone())?),
TypeKind::Borrow(type_kind, _) => types.extend(resolve_types_recursively(&type_kind, modules, seen.clone())?),
TypeKind::UserPtr(type_kind) => types.extend(resolve_types_recursively(&type_kind, modules, seen.clone())?),
TypeKind::CodegenPtr(type_kind) => types.extend(resolve_types_recursively(&type_kind, modules, seen.clone())?),
_ => {}
} }
Ok(types)
} }

View File

@ -1,271 +0,0 @@
use std::{collections::HashMap, path::PathBuf};
use crate::mir::{
self, FunctionCall, GlobalKind, GlobalValue, IfExpression, Literal, Module, SourceModuleId, TypeKind,
WhileStatement,
};
use super::pass::{Pass, PassResult, PassState};
pub trait MacroFunction: std::fmt::Debug {
fn generate<'ctx, 'a>(
&self,
module: &MacroModule,
params: &[mir::Literal],
prefix: String,
) -> Result<(Vec<GlobalValue>, mir::ExprKind), ErrorKind>;
}
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum ErrorKind {
#[error("Should never be encountered!")]
Null,
#[error("No such macro {0} defined")]
NoSuchMacro(String),
#[error("Macro arguments may only be literals")]
InvalidMacroArgs,
#[error("Got {0} parameters, expected {1}")]
InvalidAmountOfParams(u32, u32),
#[error("Expected argument type of {0}, got {1}")]
InvalidArgumentType(TypeKind, TypeKind),
#[error("Error executing macro: {0}")]
MacroExecutionError(String),
}
type MacroModuleMap = HashMap<SourceModuleId, MacroModule>;
/// Struct used to implement a type-checking pass that can be performed on the
/// MIR.
pub struct MacroPass {
pub(crate) macros: HashMap<String, Box<dyn MacroFunction>>,
pub module_map: MacroModuleMap,
}
pub struct MacroModule {
path: Option<PathBuf>,
}
impl From<&Module> for MacroModule {
fn from(value: &Module) -> Self {
MacroModule {
path: value.path.clone(),
}
}
}
type MacroPassState<'map, 'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
impl Pass for MacroPass {
type Data = ();
type TError = ErrorKind;
fn context(&mut self, _context: &mut mir::Context, mut _state: PassState<Self::Data, Self::TError>) -> PassResult {
Ok(())
}
fn module(&mut self, module: &mut mir::Module, mut state: PassState<Self::Data, Self::TError>) -> PassResult {
for function in &mut module.functions {
let globals = match &mut function.kind {
mir::FunctionDefinitionKind::Local(block, _) => block.gen_macros(self, &mut state, &self.module_map),
_ => Vec::new(),
};
module.globals.extend(globals);
}
Ok(())
}
}
impl mir::Block {
fn gen_macros(&mut self, data: &MacroPass, state: &mut MacroPassState, map: &MacroModuleMap) -> Vec<GlobalValue> {
let mut globals = Vec::new();
for statement in &mut self.statements {
globals.extend(statement.gen_macros(data, state, map));
}
if let Some((_, Some(return_expr))) = &mut self.return_expression {
globals.extend(return_expr.gen_macros(data, state, map));
}
globals
}
}
impl mir::Statement {
fn gen_macros(&mut self, data: &MacroPass, state: &mut MacroPassState, map: &MacroModuleMap) -> Vec<GlobalValue> {
let mut globals = Vec::new();
match &mut self.0 {
mir::StmtKind::Let(.., expr) => {
globals.extend(expr.gen_macros(data, state, map));
}
mir::StmtKind::Set(lhs, rhs) => {
globals.extend(lhs.gen_macros(data, state, map));
globals.extend(rhs.gen_macros(data, state, map));
}
mir::StmtKind::Import(_) => {}
mir::StmtKind::Expression(expr) => {
globals.extend(expr.gen_macros(data, state, map));
}
mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
globals.extend(condition.gen_macros(data, state, map));
globals.extend(block.gen_macros(data, state, map));
}
};
globals
}
}
impl mir::Expression {
fn gen_macros(&mut self, data: &MacroPass, state: &mut MacroPassState, map: &MacroModuleMap) -> Vec<GlobalValue> {
let mut globals = Vec::new();
match &mut self.0 {
mir::ExprKind::FunctionCall(function_call) => {
for param in &mut function_call.parameters {
globals.extend(param.gen_macros(data, state, map));
}
if function_call.is_macro {
if let Some(existing_macro) = data.macros.get(&function_call.name) {
let mut literals = Vec::new();
for param in &mut function_call.parameters {
match &param.0 {
super::ExprKind::Literal(literal) => literals.push(literal.clone()),
_ => state.note_errors(&vec![ErrorKind::InvalidMacroArgs], param.1),
}
}
let (generated_globals, expr) = state.or_else(
existing_macro
.generate(
map.get(&state.scope.module_id.unwrap()).unwrap(),
&literals,
format!(
"macro.{}.{}.{}",
function_call.name, self.1.range.start, self.1.range.end
),
)
.map(|(globals, kind)| (globals, mir::Expression(kind, self.1))),
(Vec::new(), self.clone()),
self.1,
);
globals.extend(generated_globals);
*self = expr;
} else {
state.note_errors(
&vec![ErrorKind::NoSuchMacro(function_call.name.clone())],
function_call.meta,
);
}
}
}
mir::ExprKind::Variable(_) => {}
mir::ExprKind::Indexed(expression, _, expression1) => {
globals.extend(expression.gen_macros(data, state, map));
globals.extend(expression1.gen_macros(data, state, map));
}
mir::ExprKind::Accessed(expression, ..) => {
globals.extend(expression.gen_macros(data, state, map));
}
mir::ExprKind::Array(expressions) => {
for expression in expressions {
globals.extend(expression.gen_macros(data, state, map));
}
}
mir::ExprKind::Struct(_, items) => {
for item in items {
globals.extend(item.1.gen_macros(data, state, map));
}
}
mir::ExprKind::Literal(_) => {}
mir::ExprKind::BinOp(_, expression, expression1, _) => {
globals.extend(expression.gen_macros(data, state, map));
globals.extend(expression1.gen_macros(data, state, map));
}
mir::ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => {
for expression in parameters {
globals.extend(expression.gen_macros(data, state, map));
}
}
mir::ExprKind::If(IfExpression(cond, lhs, rhs)) => {
globals.extend(cond.gen_macros(data, state, map));
globals.extend(lhs.gen_macros(data, state, map));
if let Some(rhs) = rhs.as_mut() {
globals.extend(rhs.gen_macros(data, state, map));
}
}
mir::ExprKind::Block(block) => {
globals.extend(block.gen_macros(data, state, map));
}
mir::ExprKind::Borrow(expression, _) => {
globals.extend(expression.gen_macros(data, state, map));
}
mir::ExprKind::Deref(expression) => {
globals.extend(expression.gen_macros(data, state, map));
}
mir::ExprKind::CastTo(expression, _) => {
globals.extend(expression.gen_macros(data, state, map));
}
mir::ExprKind::GlobalRef(..) => {}
}
globals
}
}
pub fn form_macros() -> HashMap<String, Box<dyn MacroFunction>> {
let mut macros: HashMap<String, Box<dyn MacroFunction>> = HashMap::new();
macros.insert("include_bytes".to_owned(), Box::new(IncludeBytes));
macros
}
#[derive(Debug)]
pub struct IncludeBytes;
impl MacroFunction for IncludeBytes {
fn generate<'ctx, 'a>(
&self,
module: &MacroModule,
literals: &[mir::Literal],
global_name: String,
) -> Result<(Vec<GlobalValue>, mir::ExprKind), ErrorKind> {
if literals.len() != 1 {
return Err(ErrorKind::InvalidAmountOfParams(literals.len() as u32, 1));
}
let literal = literals.get(0).unwrap();
let Literal::String(path) = literal else {
return Err(ErrorKind::InvalidArgumentType(
literal.as_type(),
TypeKind::UserPtr(Box::new(TypeKind::Char)),
));
};
let path = module
.path
.as_ref()
.expect("Module has no path!")
.parent()
.expect("Module path has no parent!")
.join(path);
let contents = match std::fs::read(path) {
Ok(content) => content,
Err(e) => return Err(ErrorKind::MacroExecutionError(format!("{}", e))),
};
let literals = contents
.iter()
.map(|c| GlobalKind::Literal(Literal::U8(*c)))
.collect::<Vec<_>>();
let len = literals.len();
let global = GlobalValue {
name: global_name.clone(),
kind: GlobalKind::Array(literals),
};
Ok((
vec![global.clone()],
mir::ExprKind::GlobalRef(
global_name,
TypeKind::Borrow(Box::new(TypeKind::Array(Box::new(TypeKind::U8), len as u64)), false),
),
))
}
}

View File

@ -13,7 +13,6 @@ use crate::{
mod fmt; mod fmt;
pub mod implement; pub mod implement;
pub mod linker; pub mod linker;
pub mod macros;
pub mod pass; pub mod pass;
pub mod typecheck; pub mod typecheck;
@ -41,40 +40,15 @@ impl Metadata {
} }
pub fn into_positions(&self, tokens: &Vec<FullToken>) -> Option<(Position, Position)> { pub fn into_positions(&self, tokens: &Vec<FullToken>) -> Option<(Position, Position)> {
self.range.into_position(tokens) let mut iter = tokens
} .iter()
.skip(self.range.start)
pub fn is_after(&self, token_idx: usize) -> bool { .take(self.range.end - self.range.start);
return token_idx < self.range.start; if let Some(first) = iter.next() {
} let last = iter.last().unwrap_or(first);
Some((first.position, last.position.add(last.token.len() as u32)))
pub fn is_before(&self, token_idx: usize) -> bool { } else {
return token_idx > self.range.end; None
}
pub fn contains(&self, token_idx: usize) -> bool {
return token_idx >= self.range.start && token_idx <= self.range.end;
}
pub fn after(&self, cutoff: usize) -> Metadata {
Metadata {
source_module_id: self.source_module_id,
range: TokenRange {
start: cutoff.max(self.range.start),
end: cutoff.max(self.range.end),
},
position: None,
}
}
pub fn before(&self, cutoff: usize) -> Metadata {
Metadata {
source_module_id: self.source_module_id,
range: TokenRange {
start: cutoff.min(self.range.start),
end: cutoff.min(self.range.end),
},
position: None,
} }
} }
} }
@ -105,7 +79,7 @@ impl TokenRange {
#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct CustomTypeKey(pub String, pub SourceModuleId); pub struct CustomTypeKey(pub String, pub SourceModuleId);
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TypeKind { pub enum TypeKind {
Bool, Bool,
I8, I8,
@ -120,7 +94,7 @@ pub enum TypeKind {
U128, U128,
Void, Void,
F16, F16,
F16B, F32B,
F32, F32,
F64, F64,
F128, F128,
@ -220,7 +194,7 @@ impl Literal {
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Integer), Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Integer),
Literal::Vague(VagueLiteral::Decimal(_)) => TypeKind::Vague(VagueType::Decimal), Literal::Vague(VagueLiteral::Decimal(_)) => TypeKind::Vague(VagueType::Decimal),
Literal::F16(_) => TypeKind::F16, Literal::F16(_) => TypeKind::F16,
Literal::F32B(_) => TypeKind::F16B, Literal::F32B(_) => TypeKind::F32B,
Literal::F32(_) => TypeKind::F32, Literal::F32(_) => TypeKind::F32,
Literal::F64(_) => TypeKind::F64, Literal::F64(_) => TypeKind::F64,
Literal::F80(_) => TypeKind::F80, Literal::F80(_) => TypeKind::F80,
@ -278,15 +252,15 @@ pub enum ReturnKind {
pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata); pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Import(pub Vec<(String, Metadata)>, pub Metadata); pub struct Import(pub Vec<String>, pub Metadata);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ExprKind { pub enum ExprKind {
Variable(NamedVariableRef), Variable(NamedVariableRef),
Indexed(Box<Expression>, TypeKind, Box<Expression>), Indexed(Box<Expression>, TypeKind, Box<Expression>),
Accessed(Box<Expression>, TypeKind, String, Metadata), Accessed(Box<Expression>, TypeKind, String),
Array(Vec<Expression>), Array(Vec<Expression>),
Struct(CustomTypeKey, Vec<(String, Expression, Metadata)>), Struct(String, Vec<(String, Expression)>),
Literal(Literal), Literal(Literal),
BinOp(BinaryOperator, Box<Expression>, Box<Expression>, TypeKind), BinOp(BinaryOperator, Box<Expression>, Box<Expression>, TypeKind),
FunctionCall(FunctionCall), FunctionCall(FunctionCall),
@ -296,7 +270,6 @@ pub enum ExprKind {
Borrow(Box<Expression>, bool), Borrow(Box<Expression>, bool),
Deref(Box<Expression>), Deref(Box<Expression>),
CastTo(Box<Expression>, TypeKind), CastTo(Box<Expression>, TypeKind),
GlobalRef(String, TypeKind),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -311,41 +284,20 @@ pub struct FunctionCall {
pub name: String, pub name: String,
pub return_type: TypeKind, pub return_type: TypeKind,
pub parameters: Vec<Expression>, pub parameters: Vec<Expression>,
pub is_macro: bool,
pub meta: Metadata, pub meta: Metadata,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct FunctionDefinition { pub struct FunctionDefinition {
pub name: String, pub name: String,
pub documentation: Option<String>,
pub linkage_name: Option<String>, pub linkage_name: Option<String>,
/// Whether this function is visible to outside modules /// Whether this function is visible to outside modules
pub is_pub: bool, pub is_pub: bool,
/// Whether this module is from an external module, and has been imported /// Whether this module is from an external module, and has been imported
pub is_imported: bool, pub is_imported: bool,
pub return_type: TypeKind, pub return_type: TypeKind,
pub parameters: Vec<FunctionParam>, pub parameters: Vec<(String, TypeKind)>,
pub kind: FunctionDefinitionKind, pub kind: FunctionDefinitionKind,
pub source: Option<SourceModuleId>,
pub signature_meta: Metadata,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct FunctionParam {
pub name: String,
pub ty: TypeKind,
pub meta: Metadata,
}
impl FunctionParam {
pub fn from<T: Into<String>>(name: T, ty: TypeKind) -> FunctionParam {
FunctionParam {
name: name.into(),
ty: ty,
meta: Default::default(),
}
}
} }
pub enum SelfKind { pub enum SelfKind {
@ -374,7 +326,11 @@ impl FunctionDefinition {
} }
pub fn signature(&self) -> Metadata { pub fn signature(&self) -> Metadata {
self.signature_meta match &self.kind {
FunctionDefinitionKind::Local(_, metadata) => metadata.clone(),
FunctionDefinitionKind::Extern(_) => Metadata::default(),
FunctionDefinitionKind::Intrinsic(_) => Metadata::default(),
}
} }
} }
@ -422,9 +378,9 @@ pub enum TypeDefinitionKind {
#[derive(Debug)] #[derive(Debug)]
pub struct BinopDefinition { pub struct BinopDefinition {
pub lhs: FunctionParam, pub lhs: (String, TypeKind),
pub op: BinaryOperator, pub op: BinaryOperator,
pub rhs: FunctionParam, pub rhs: (String, TypeKind),
pub return_type: TypeKind, pub return_type: TypeKind,
pub fn_kind: FunctionDefinitionKind, pub fn_kind: FunctionDefinitionKind,
pub meta: Metadata, pub meta: Metadata,
@ -455,24 +411,11 @@ pub struct Module {
pub functions: Vec<FunctionDefinition>, pub functions: Vec<FunctionDefinition>,
pub typedefs: Vec<TypeDefinition>, pub typedefs: Vec<TypeDefinition>,
pub binop_defs: Vec<BinopDefinition>, pub binop_defs: Vec<BinopDefinition>,
pub globals: Vec<GlobalValue>,
pub path: Option<PathBuf>, pub path: Option<PathBuf>,
pub tokens: Vec<FullToken>, pub tokens: Vec<FullToken>,
pub is_main: bool, pub is_main: bool,
} }
#[derive(Debug, Clone)]
pub struct GlobalValue {
pub name: String,
pub kind: GlobalKind,
}
#[derive(Debug, Clone)]
pub enum GlobalKind {
Literal(Literal),
Array(Vec<GlobalKind>),
}
pub type ModuleMap = HashMap<SourceModuleId, Module>; pub type ModuleMap = HashMap<SourceModuleId, Module>;
#[derive(Debug)] #[derive(Debug)]

View File

@ -187,7 +187,7 @@ impl<Data: Clone + Default> Scope<Data> {
key.clone(), key.clone(),
ScopeFunction { ScopeFunction {
ret: func.return_type, ret: func.return_type,
params: func.parameters.iter().map(|p| p.ty.clone()).collect(), params: func.parameters.iter().map(|(_, p)| p.clone()).collect(),
}, },
) )
.unwrap(); .unwrap();
@ -369,11 +369,11 @@ impl Context {
.binops .binops
.set( .set(
BinopKey { BinopKey {
params: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()), params: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
operator: intrinsic.op, operator: intrinsic.op,
}, },
ScopeBinopDef { ScopeBinopDef {
hands: (intrinsic.lhs.ty.clone(), intrinsic.rhs.ty.clone()), hands: (intrinsic.lhs.1.clone(), intrinsic.rhs.1.clone()),
operator: intrinsic.op, operator: intrinsic.op,
return_ty: intrinsic.return_type.clone(), return_ty: intrinsic.return_type.clone(),
}, },
@ -407,11 +407,11 @@ impl Module {
.binops .binops
.set( .set(
BinopKey { BinopKey {
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()), params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
operator: binop.op, operator: binop.op,
}, },
ScopeBinopDef { ScopeBinopDef {
hands: (binop.lhs.ty.clone(), binop.rhs.ty.clone()), hands: (binop.lhs.1.clone(), binop.rhs.1.clone()),
operator: binop.op, operator: binop.op,
return_ty: binop.return_type.clone(), return_ty: binop.return_type.clone(),
}, },
@ -426,7 +426,7 @@ impl Module {
function.name.clone(), function.name.clone(),
ScopeFunction { ScopeFunction {
ret: function.return_type.clone(), ret: function.return_type.clone(),
params: function.parameters.iter().cloned().map(|v| v.ty).collect(), params: function.parameters.iter().cloned().map(|v| v.1).collect(),
}, },
) )
.ok(); .ok();
@ -439,7 +439,7 @@ impl Module {
AssociatedFunctionKey(ty.clone(), function.name.clone()), AssociatedFunctionKey(ty.clone(), function.name.clone()),
ScopeFunction { ScopeFunction {
ret: function.return_type.clone(), ret: function.return_type.clone(),
params: function.parameters.iter().cloned().map(|v| v.ty).collect(), params: function.parameters.iter().cloned().map(|v| v.1).collect(),
}, },
) )
.ok(); .ok();
@ -450,10 +450,6 @@ impl Module {
for function in &mut self.functions { for function in &mut self.functions {
function.pass(pass, state, &mut scope.inner(), self.module_id)?; function.pass(pass, state, &mut scope.inner(), self.module_id)?;
} }
for (_, function) in &mut self.associated_functions {
function.pass(pass, state, &mut scope.inner(), self.module_id)?;
}
Ok(()) Ok(())
} }
} }
@ -470,9 +466,9 @@ impl FunctionDefinition {
scope scope
.variables .variables
.set( .set(
param.name.clone(), param.0.clone(),
ScopeVariable { ScopeVariable {
ty: param.ty.clone(), ty: param.1.clone(),
mutable: false, mutable: false,
}, },
) )
@ -507,10 +503,6 @@ impl Block {
statement.pass(pass, state, &mut scope, mod_id)?; statement.pass(pass, state, &mut scope, mod_id)?;
} }
if let Some((_, Some(return_expr))) = &mut self.return_expression {
return_expr.pass(pass, state, &mut scope, mod_id)?;
}
pass.block(self, PassState::from(state, &mut scope, Some(mod_id))) pass.block(self, PassState::from(state, &mut scope, Some(mod_id)))
} }
} }
@ -589,7 +581,7 @@ impl Expression {
} }
} }
ExprKind::Struct(_, items) => { ExprKind::Struct(_, items) => {
for (_, expr, _) in items { for (_, expr) in items {
expr.pass(pass, state, scope, mod_id)?; expr.pass(pass, state, scope, mod_id)?;
} }
} }
@ -619,7 +611,6 @@ impl Expression {
ExprKind::Borrow(expression, _) => expression.pass(pass, state, scope, mod_id)?, ExprKind::Borrow(expression, _) => expression.pass(pass, state, scope, mod_id)?,
ExprKind::Deref(expression) => expression.pass(pass, state, scope, mod_id)?, ExprKind::Deref(expression) => expression.pass(pass, state, scope, mod_id)?,
ExprKind::CastTo(expression, _) => expression.pass(pass, state, scope, mod_id)?, ExprKind::CastTo(expression, _) => expression.pass(pass, state, scope, mod_id)?,
ExprKind::GlobalRef(..) => {}
} }
Ok(()) Ok(())
} }

View File

@ -88,8 +88,6 @@ pub enum ErrorKind {
InvalidBinop(BinaryOperator, TypeKind, TypeKind), InvalidBinop(BinaryOperator, TypeKind, TypeKind),
#[error("Could not infer type for {0:?}. Try adding type annotations.")] #[error("Could not infer type for {0:?}. Try adding type annotations.")]
CouldNotInferType(String), CouldNotInferType(String),
#[error("Arguments for a macro-function may only contain literals")]
MacroMustBeLiterals,
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -141,7 +139,7 @@ impl TypeKind {
| TypeKind::U64 | TypeKind::U64
| TypeKind::U128 | TypeKind::U128
| TypeKind::F16 | TypeKind::F16
| TypeKind::F16B | TypeKind::F32B
| TypeKind::F32 | TypeKind::F32
| TypeKind::F64 | TypeKind::F64
| TypeKind::F80 | TypeKind::F80
@ -153,7 +151,7 @@ impl TypeKind {
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)), TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Decimal)),
TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)), TypeKind::Vague(Vague::Decimal) => Ok(TypeKind::Vague(Vague::Decimal)),
TypeKind::F16 TypeKind::F16
| TypeKind::F16B | TypeKind::F32B
| TypeKind::F32 | TypeKind::F32
| TypeKind::F64 | TypeKind::F64
| TypeKind::F80 | TypeKind::F80
@ -207,7 +205,7 @@ impl TypeKind {
}, },
(TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => match other { (TypeKind::Vague(Vague::Decimal), other) | (other, TypeKind::Vague(Vague::Decimal)) => match other {
TypeKind::F16 TypeKind::F16
| TypeKind::F16B | TypeKind::F32B
| TypeKind::F32 | TypeKind::F32
| TypeKind::F64 | TypeKind::F64
| TypeKind::F80 | TypeKind::F80
@ -256,16 +254,6 @@ impl TypeKind {
let other_cat = other.category(); let other_cat = other.category();
match (self, other) { match (self, other) {
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Ok(other.clone()), (TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Ok(other.clone()),
(TypeKind::Borrow(ty1, _), TypeKind::UserPtr(ty2)) => match *ty1.clone() {
TypeKind::Array(ty1, _) => {
if ty1 == *ty2 {
Ok(other.clone())
} else {
Err(ErrorKind::NotCastableTo(self.clone(), other.clone()))
}
}
_ => Err(ErrorKind::NotCastableTo(self.clone(), other.clone())),
},
(TypeKind::Char, TypeKind::U8) => Ok(other.clone()), (TypeKind::Char, TypeKind::U8) => Ok(other.clone()),
(TypeKind::U8, TypeKind::Char) => Ok(other.clone()), (TypeKind::U8, TypeKind::Char) => Ok(other.clone()),
_ => match (&self_cat, &other_cat) { _ => match (&self_cat, &other_cat) {
@ -333,7 +321,7 @@ impl TypeKind {
.map(|_| ()) .map(|_| ())
.ok_or(ErrorKind::NoSuchType( .ok_or(ErrorKind::NoSuchType(
custom_type_key.0.clone(), custom_type_key.0.clone(),
custom_type_key.1.clone(), state.module_id.unwrap(),
)) ))
} }
TypeKind::Borrow(type_kind, _) => type_kind.is_known(state), TypeKind::Borrow(type_kind, _) => type_kind.is_known(state),

View File

@ -84,7 +84,7 @@ impl<'t> Pass for TypeCheck<'t> {
fn check_typedefs_for_recursion<'a, 'b>( fn check_typedefs_for_recursion<'a, 'b>(
defmap: &'b HashMap<&'a String, &'b TypeDefinition>, defmap: &'b HashMap<&'a String, &'b TypeDefinition>,
typedef: &'b TypeDefinition, typedef: &'b TypeDefinition,
seen: HashSet<String>, mut seen: HashSet<String>,
state: &mut TypecheckPassState, state: &mut TypecheckPassState,
) { ) {
match &typedef.kind { match &typedef.kind {
@ -97,10 +97,9 @@ fn check_typedefs_for_recursion<'a, 'b>(
typedef.meta, typedef.meta,
); );
} else { } else {
seen.insert(name.clone());
if let Some(inner_typedef) = defmap.get(name) { if let Some(inner_typedef) = defmap.get(name) {
let mut inner_seen = seen.clone(); check_typedefs_for_recursion(defmap, inner_typedef, seen.clone(), state)
inner_seen.insert(name.clone());
check_typedefs_for_recursion(defmap, inner_typedef, inner_seen.clone(), state)
} }
} }
} }
@ -113,7 +112,7 @@ impl BinopDefinition {
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> { fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> {
for param in vec![&self.lhs, &self.rhs] { for param in vec![&self.lhs, &self.rhs] {
let param_t = state.or_else( let param_t = state.or_else(
param.ty.assert_known(state), param.1.assert_known(state),
TypeKind::Vague(Vague::Unknown), TypeKind::Vague(Vague::Unknown),
self.signature(), self.signature(),
); );
@ -121,13 +120,13 @@ impl BinopDefinition {
.scope .scope
.variables .variables
.set( .set(
param.name.clone(), param.0.clone(),
ScopeVariable { ScopeVariable {
ty: param_t.clone(), ty: param_t.clone(),
mutable: param_t.is_mutable(), mutable: param_t.is_mutable(),
}, },
) )
.or(Err(ErrorKind::VariableAlreadyDefined(param.name.clone()))); .or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
state.ok(res, self.signature()); state.ok(res, self.signature());
} }
@ -151,7 +150,7 @@ impl FunctionDefinition {
fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> { fn typecheck(&mut self, typerefs: &TypeRefs, state: &mut TypecheckPassState) -> Result<TypeKind, ErrorKind> {
for param in &self.parameters { for param in &self.parameters {
let param_t = state.or_else( let param_t = state.or_else(
param.ty.assert_known(state), param.1.assert_known(state),
TypeKind::Vague(Vague::Unknown), TypeKind::Vague(Vague::Unknown),
self.signature(), self.signature(),
); );
@ -159,13 +158,13 @@ impl FunctionDefinition {
.scope .scope
.variables .variables
.set( .set(
param.name.clone(), param.0.clone(),
ScopeVariable { ScopeVariable {
ty: param_t.clone(), ty: param_t.clone(),
mutable: param_t.is_mutable(), mutable: param_t.is_mutable(),
}, },
) )
.or(Err(ErrorKind::VariableAlreadyDefined(param.name.clone()))); .or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
state.ok(res, self.signature()); state.ok(res, self.signature());
} }
@ -194,7 +193,7 @@ impl FunctionDefinitionKind {
block.typecheck(&mut state.inner(), &typerefs, hint.into()) block.typecheck(&mut state.inner(), &typerefs, hint.into())
} }
FunctionDefinitionKind::Extern(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))), FunctionDefinitionKind::Extern(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
FunctionDefinitionKind::Intrinsic(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))), FunctionDefinitionKind::Intrinsic(..) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
} }
} }
} }
@ -597,7 +596,7 @@ impl Expression {
} }
} }
} }
ExprKind::Accessed(expression, type_kind, field_name, _) => { ExprKind::Accessed(expression, type_kind, field_name) => {
// Resolve expected type // Resolve expected type
let expected_ty = type_kind.resolve_ref(typerefs); let expected_ty = type_kind.resolve_ref(typerefs);
@ -621,31 +620,32 @@ impl Expression {
// Update possibly resolved type // Update possibly resolved type
Ok(true_ty) Ok(true_ty)
} else { } else {
Err(ErrorKind::NoSuchField(key.0.clone())) Err(ErrorKind::NoSuchField(field_name.clone()))
} }
} else { } else {
Err(ErrorKind::TriedAccessingNonStruct(expr_ty)) Err(ErrorKind::TriedAccessingNonStruct(expr_ty))
} }
} }
ExprKind::Struct(struct_key, items) => { ExprKind::Struct(struct_name, items) => {
let type_key = CustomTypeKey(struct_name.clone(), state.module_id.unwrap());
let struct_def = state let struct_def = state
.scope .scope
.get_struct_type(&struct_key) .get_struct_type(&type_key)
.ok_or(ErrorKind::NoSuchType(struct_key.0.clone(), struct_key.1))? .ok_or(ErrorKind::NoSuchType(struct_name.clone(), type_key.1))?
.clone(); .clone();
let mut expected_fields = if let Some(struct_ty) = state.scope.get_struct_type(&struct_key) { 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() struct_ty.0.iter().map(|f| f.0.clone()).collect()
} else { } else {
HashSet::new() HashSet::new()
}; };
for (field_name, field_expr, _) in items { for (field_name, field_expr) in items {
// Get expected type, or error if field does not exist // Get expected type, or error if field does not exist
let expected_ty = state.or_else( let expected_ty = state.or_else(
struct_def struct_def
.get_field_ty(field_name) .get_field_ty(field_name)
.ok_or(ErrorKind::NoSuchField(format!("{:?}.{}", struct_key, field_name))), .ok_or(ErrorKind::NoSuchField(format!("{}.{}", struct_name, field_name))),
&TypeKind::Vague(VagueType::Unknown), &TypeKind::Vague(VagueType::Unknown),
field_expr.1, field_expr.1,
); );
@ -667,7 +667,7 @@ impl Expression {
self.1, self.1,
); );
Ok(TypeKind::CustomType(struct_key.clone())) Ok(TypeKind::CustomType(type_key))
} }
ExprKind::Borrow(expr, mutable) => { ExprKind::Borrow(expr, mutable) => {
let hint_t = if let HintKind::Coerce(hint_t) = hint_t { let hint_t = if let HintKind::Coerce(hint_t) = hint_t {
@ -720,19 +720,15 @@ impl Expression {
expr.resolve_ref(typerefs).cast_into(type_kind) expr.resolve_ref(typerefs).cast_into(type_kind)
} }
ExprKind::AssociatedFunctionCall(type_kind, function_call) => { ExprKind::AssociatedFunctionCall(type_kind, function_call) => {
*type_kind = type_kind.or_default()?;
let true_function = state let true_function = state
.scope .scope
.get_associated_function(&pass::AssociatedFunctionKey( .get_associated_function(&pass::AssociatedFunctionKey(
type_kind.clone(), type_kind.clone(),
function_call.name.clone(), function_call.name.clone(),
)) ))
.ok_or(ErrorKind::AssocFunctionNotDefined( .ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()));
function_call.name.clone(),
type_kind.clone(),
));
if let Some(f) = state.ok(true_function, function_call.meta) { if let Some(f) = state.ok(true_function, self.1) {
let param_len_given = function_call.parameters.len(); let param_len_given = function_call.parameters.len();
let param_len_expected = f.params.len(); let param_len_expected = f.params.len();
@ -771,10 +767,6 @@ impl Expression {
Ok(function_call.return_type.clone().resolve_ref(typerefs)) Ok(function_call.return_type.clone().resolve_ref(typerefs))
} }
} }
ExprKind::GlobalRef(..) => Ok(self
.return_type(typerefs, state.scope.module_id.unwrap())
.map(|r| r.1)
.unwrap()),
} }
} }
} }
@ -806,14 +798,14 @@ impl Literal {
(L::Vague(VagueL::Number(v)), TypeKind::U128) => L::U128(v as u128), (L::Vague(VagueL::Number(v)), TypeKind::U128) => L::U128(v as u128),
(L::Vague(VagueL::Number(v)), TypeKind::F16) => L::F16(v as f32), (L::Vague(VagueL::Number(v)), TypeKind::F16) => L::F16(v as f32),
(L::Vague(VagueL::Number(v)), TypeKind::F32) => L::F32(v as f32), (L::Vague(VagueL::Number(v)), TypeKind::F32) => L::F32(v as f32),
(L::Vague(VagueL::Number(v)), TypeKind::F16B) => L::F32B(v as f32), (L::Vague(VagueL::Number(v)), TypeKind::F32B) => L::F32B(v as f32),
(L::Vague(VagueL::Number(v)), TypeKind::F64) => L::F64(v as f64), (L::Vague(VagueL::Number(v)), TypeKind::F64) => L::F64(v as f64),
(L::Vague(VagueL::Number(v)), TypeKind::F80) => L::F80(v as f64), (L::Vague(VagueL::Number(v)), TypeKind::F80) => L::F80(v as f64),
(L::Vague(VagueL::Number(v)), TypeKind::F128) => L::F128(v as f64), (L::Vague(VagueL::Number(v)), TypeKind::F128) => L::F128(v as f64),
(L::Vague(VagueL::Number(v)), TypeKind::F128PPC) => L::F128PPC(v as f64), (L::Vague(VagueL::Number(v)), TypeKind::F128PPC) => L::F128PPC(v as f64),
(L::Vague(VagueL::Decimal(v)), TypeKind::F16) => L::F16(v as f32), (L::Vague(VagueL::Decimal(v)), TypeKind::F16) => L::F16(v as f32),
(L::Vague(VagueL::Decimal(v)), TypeKind::F32) => L::F32(v as f32), (L::Vague(VagueL::Decimal(v)), TypeKind::F32) => L::F32(v as f32),
(L::Vague(VagueL::Decimal(v)), TypeKind::F16B) => L::F32B(v as f32), (L::Vague(VagueL::Decimal(v)), TypeKind::F32B) => L::F32B(v as f32),
(L::Vague(VagueL::Decimal(v)), TypeKind::F64) => L::F64(v as f64), (L::Vague(VagueL::Decimal(v)), TypeKind::F64) => L::F64(v as f64),
(L::Vague(VagueL::Decimal(v)), TypeKind::F80) => L::F80(v as f64), (L::Vague(VagueL::Decimal(v)), TypeKind::F80) => L::F80(v as f64),
(L::Vague(VagueL::Decimal(v)), TypeKind::F128) => L::F128(v as f64), (L::Vague(VagueL::Decimal(v)), TypeKind::F128) => L::F128(v as f64),

View File

@ -12,10 +12,9 @@ use std::{
use crate::{ use crate::{
mir::{ mir::{
implement::TypeCategory,
pass::{AssociatedFunctionKey, ScopeVariable}, pass::{AssociatedFunctionKey, ScopeVariable},
BinopDefinition, Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression, Module, BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
ReturnKind, StmtKind, TypeKind, VagueType, WhileStatement, IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
}, },
util::try_all, util::try_all,
}; };
@ -88,16 +87,16 @@ impl<'t> Pass for TypeInference<'t> {
let mut seen_binops = HashSet::new(); let mut seen_binops = HashSet::new();
for binop in &module.binop_defs { for binop in &module.binop_defs {
let binop_key = BinopKey { let binop_key = BinopKey {
params: (binop.lhs.ty.clone(), binop.rhs.ty.clone()), params: (binop.lhs.1.clone(), binop.rhs.1.clone()),
operator: binop.op, operator: binop.op,
}; };
if seen_binops.contains(&binop_key) || (binop.lhs == binop.rhs && binop.lhs.ty.category().is_simple_maths()) if seen_binops.contains(&binop_key) || (binop.lhs == binop.rhs && binop.lhs.1.category().is_simple_maths())
{ {
state.note_errors( state.note_errors(
&vec![ErrorKind::BinaryOpAlreadyDefined( &vec![ErrorKind::BinaryOpAlreadyDefined(
binop.op, binop.op,
binop.lhs.ty.clone(), binop.lhs.1.clone(),
binop.rhs.ty.clone(), binop.rhs.1.clone(),
)], )],
binop.signature(), binop.signature(),
); );
@ -108,7 +107,7 @@ impl<'t> Pass for TypeInference<'t> {
.set( .set(
binop_key, binop_key,
crate::mir::pass::ScopeBinopDef { crate::mir::pass::ScopeBinopDef {
hands: (binop.lhs.ty.clone(), binop.rhs.ty.clone()), hands: (binop.lhs.1.clone(), binop.rhs.1.clone()),
operator: binop.op, operator: binop.op,
return_ty: binop.return_type.clone(), return_ty: binop.return_type.clone(),
}, },
@ -139,20 +138,20 @@ impl BinopDefinition {
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> { fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> {
let scope_hints = ScopeTypeRefs::from(type_refs); let scope_hints = ScopeTypeRefs::from(type_refs);
let lhs_ty = state.or_else(self.lhs.ty.assert_unvague(), Vague(Unknown), self.signature()); let lhs_ty = state.or_else(self.lhs.1.assert_unvague(), Vague(Unknown), self.signature());
state.ok( state.ok(
scope_hints scope_hints
.new_var(self.lhs.name.clone(), false, &lhs_ty) .new_var(self.lhs.0.clone(), false, &lhs_ty)
.or(Err(ErrorKind::VariableAlreadyDefined(self.lhs.name.clone()))), .or(Err(ErrorKind::VariableAlreadyDefined(self.lhs.0.clone()))),
self.signature(), self.signature(),
); );
let rhs_ty = state.or_else(self.rhs.ty.assert_unvague(), Vague(Unknown), self.signature()); let rhs_ty = state.or_else(self.rhs.1.assert_unvague(), Vague(Unknown), self.signature());
state.ok( state.ok(
scope_hints scope_hints
.new_var(self.rhs.name.clone(), false, &rhs_ty) .new_var(self.rhs.0.clone(), false, &rhs_ty)
.or(Err(ErrorKind::VariableAlreadyDefined(self.rhs.name.clone()))), .or(Err(ErrorKind::VariableAlreadyDefined(self.rhs.0.clone()))),
self.signature(), self.signature(),
); );
@ -171,11 +170,10 @@ impl FunctionDefinition {
fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> { fn infer_types(&mut self, type_refs: &TypeRefs, state: &mut TypecheckPassState) -> Result<(), ErrorKind> {
let scope_refs = ScopeTypeRefs::from(type_refs); let scope_refs = ScopeTypeRefs::from(type_refs);
for param in &self.parameters { for param in &self.parameters {
let param_t = state.or_else(param.ty.assert_unvague(), Vague(Unknown), self.signature()); let param_t = state.or_else(param.1.assert_unvague(), Vague(Unknown), self.signature());
let mutable = matches!(param_t, TypeKind::Borrow(_, true));
let res = scope_refs let res = scope_refs
.new_var(param.name.clone(), mutable, &param_t) .new_var(param.0.clone(), false, &param_t)
.or(Err(ErrorKind::VariableAlreadyDefined(param.name.clone()))); .or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
state.ok(res, self.signature()); state.ok(res, self.signature());
} }
@ -383,7 +381,6 @@ impl Expression {
} else { } else {
Vec::new() Vec::new()
}; };
if binops.len() > 0 { if binops.len() > 0 {
let binop = unsafe { binops.get_unchecked(0) }; let binop = unsafe { binops.get_unchecked(0) };
let mut widened_lhs = binop.hands.0.clone(); let mut widened_lhs = binop.hands.0.clone();
@ -393,6 +390,9 @@ impl Expression {
widened_rhs = widened_rhs.widen_into(&binop.hands.1); widened_rhs = widened_rhs.widen_into(&binop.hands.1);
} }
let binop_res = type_refs.from_binop(*op, &lhs_ref, &rhs_ref); let binop_res = type_refs.from_binop(*op, &lhs_ref, &rhs_ref);
// dbg!(&return_ty);
// dbg!(&binop_res);
// dbg!(&lhs_ref, &rhs_ref, &binops, &widened_lhs, &widened_rhs);
lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap()); lhs_ref.narrow(&type_refs.from_type(&widened_lhs).unwrap());
rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap()); rhs_ref.narrow(&type_refs.from_type(&widened_rhs).unwrap());
*return_ty = binop_res.as_type(); *return_ty = binop_res.as_type();
@ -526,7 +526,7 @@ impl Expression {
} }
} }
} }
ExprKind::Accessed(expression, type_kind, field_name, _) => { ExprKind::Accessed(expression, type_kind, field_name) => {
let expr_ty = expression.infer_types(state, type_refs)?; let expr_ty = expression.infer_types(state, type_refs)?;
// Check that the resolved type is at least a struct, no // Check that the resolved type is at least a struct, no
@ -545,17 +545,18 @@ impl Expression {
*type_kind = elem_ty.as_type().clone(); *type_kind = elem_ty.as_type().clone();
Ok(elem_ty) Ok(elem_ty)
} }
None => Ok(type_refs.from_type(&TypeKind::Vague(VagueType::Unknown)).unwrap()), None => Err(ErrorKind::NoSuchField(field_name.clone())),
} }
} }
_ => Ok(type_refs.from_type(&TypeKind::Vague(VagueType::Unknown)).unwrap()), _ => Err(ErrorKind::TriedAccessingNonStruct(kind)),
} }
} }
ExprKind::Struct(struct_key, fields) => { ExprKind::Struct(struct_name, fields) => {
let type_key = CustomTypeKey(struct_name.clone(), state.module_id.unwrap());
let expected_struct_ty = state let expected_struct_ty = state
.scope .scope
.get_struct_type(&struct_key) .get_struct_type(&type_key)
.ok_or(ErrorKind::NoSuchType(struct_key.0.clone(), state.module_id.unwrap()))? .ok_or(ErrorKind::NoSuchType(struct_name.clone(), state.module_id.unwrap()))?
.clone(); .clone();
for field in fields { for field in fields {
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) { if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
@ -565,12 +566,12 @@ impl Expression {
} }
} else { } else {
state.ok::<_, Infallible>( state.ok::<_, Infallible>(
Err(ErrorKind::NoSuchField(format!("{:?}.{}", struct_key, field.0))), Err(ErrorKind::NoSuchField(format!("{}.{}", struct_name, field.0))),
field.1 .1, field.1 .1,
); );
} }
} }
Ok(type_refs.from_type(&TypeKind::CustomType(struct_key.clone())).unwrap()) Ok(type_refs.from_type(&TypeKind::CustomType(type_key.clone())).unwrap())
} }
ExprKind::Borrow(expr, mutable) => { ExprKind::Borrow(expr, mutable) => {
// Find variable type // Find variable type
@ -604,7 +605,7 @@ impl Expression {
.parameters .parameters
.get_mut(0) .get_mut(0)
.expect("Unknown-type associated function NEEDS to always have at least one parameter!"); .expect("Unknown-type associated function NEEDS to always have at least one parameter!");
let param_ty = first_param.infer_types(state, type_refs)?.resolve_deep(); let param_ty = first_param.infer_types(state, type_refs).unwrap().resolve_deep();
*type_kind = state *type_kind = state
.or_else( .or_else(
param_ty.ok_or(ErrorKind::CouldNotInferType(format!("{}", first_param))), param_ty.ok_or(ErrorKind::CouldNotInferType(format!("{}", first_param))),
@ -612,44 +613,24 @@ impl Expression {
first_param.1, first_param.1,
) )
.resolve_ref(type_refs.types); .resolve_ref(type_refs.types);
let backing_var = first_param.backing_var(); let backing_var = first_param.backing_var().expect("todo").1.clone();
let is_mutable = if let Some(backing_var) = first_param.backing_var() {
if let Some((mutable, _)) = type_refs.find_var(&backing_var.1) {
mutable
} else {
return Err(ErrorKind::VariableNotDefined(backing_var.1.clone()));
}
} else {
false
};
if backing_var.is_some() { if let TypeKind::Borrow(inner, _) = type_kind {
if let TypeKind::Borrow(inner, _) = type_kind { if let TypeKind::Borrow(..) = *inner.clone() {
let ty_cat = inner.category(); *type_kind = type_kind.unroll_borrow();
if let TypeKind::Borrow(..) = *inner.clone() { let ExprKind::Borrow(val, _) = &first_param.0 else {
*type_kind = type_kind.unroll_borrow(); panic!()
let ExprKind::Borrow(val, _) = &first_param.0 else { };
panic!()
};
*first_param = *val.clone();
} else if ty_cat == TypeCategory::Integer || ty_cat == TypeCategory::Real {
if let ExprKind::Borrow(val, _) = &first_param.0 {
*first_param = *val.clone();
}
*type_kind = *inner.clone();
}
}
} else {
if let ExprKind::Borrow(val, _) = &first_param.0 {
*first_param = *val.clone(); *first_param = *val.clone();
} }
if let TypeKind::Borrow(inner_ty, _) = type_kind {
*type_kind = *inner_ty.clone();
}
} }
if !is_mutable { if let Some((mutable, _)) = type_refs.find_var(&backing_var) {
first_param.remove_borrow_mutability(); if !mutable {
first_param.remove_borrow_mutability();
}
} else {
return Err(ErrorKind::VariableNotDefined(backing_var));
} }
} }
} }
@ -661,13 +642,9 @@ impl Expression {
.ok_or(ErrorKind::AssocFunctionNotDefined( .ok_or(ErrorKind::AssocFunctionNotDefined(
function_call.name.clone(), function_call.name.clone(),
type_kind.clone(), type_kind.clone(),
)) ))?
.clone(); .clone();
let Ok(fn_call) = fn_call else {
return Ok(type_refs.from_type(&Vague(Unknown)).unwrap());
};
// Infer param expression types and narrow them to the // Infer param expression types and narrow them to the
// expected function parameters (or Unknown types if too // expected function parameters (or Unknown types if too
// many were provided) // many were provided)
@ -683,10 +660,6 @@ impl Expression {
// Provide function return type // Provide function return type
Ok(type_refs.from_type(&fn_call.ret).unwrap()) Ok(type_refs.from_type(&fn_call.ret).unwrap())
} }
ExprKind::GlobalRef(..) => Ok(self
.return_type(type_refs.types, state.scope.module_id.unwrap())
.map(|r| type_refs.from_type(&r.1).unwrap())
.unwrap()),
} }
} }

View File

@ -97,9 +97,6 @@ pub struct TypeRefs {
/// Indirect ID-references, referring to hints-vec /// Indirect ID-references, referring to hints-vec
pub(super) type_refs: RefCell<Vec<TypeIdRef>>, pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
pub(super) binop_types: BinopMap, pub(super) binop_types: BinopMap,
/// Used when the real typerefs are not available, and any TypeRefs need to
/// be resolved as Unknown.
pub unknown_typerefs: bool,
} }
impl std::fmt::Display for TypeRefs { impl std::fmt::Display for TypeRefs {
@ -125,14 +122,6 @@ impl TypeRefs {
hints: Default::default(), hints: Default::default(),
type_refs: Default::default(), type_refs: Default::default(),
binop_types: binops, binop_types: binops,
unknown_typerefs: false,
}
}
pub fn unknown() -> TypeRefs {
TypeRefs {
unknown_typerefs: true,
..Default::default()
} }
} }
@ -188,12 +177,8 @@ impl TypeRefs {
} }
pub fn retrieve_typeref(&self, idx: usize) -> Option<TypeRefKind> { pub fn retrieve_typeref(&self, idx: usize) -> Option<TypeRefKind> {
if !self.unknown_typerefs { let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() };
let inner_idx = unsafe { *self.recurse_type_ref(idx).borrow() }; self.hints.borrow().get(inner_idx).cloned()
self.hints.borrow().get(inner_idx).cloned()
} else {
Some(TypeRefKind::Direct(TypeKind::Vague(VagueType::Unknown)))
}
} }
pub fn retrieve_wide_type(&self, idx: usize, seen: &mut HashSet<usize>) -> Option<TypeKind> { pub fn retrieve_wide_type(&self, idx: usize, seen: &mut HashSet<usize>) -> Option<TypeKind> {
@ -308,23 +293,12 @@ impl<'outer> ScopeTypeRefs<'outer> {
let lhs_resolved = lhs.resolve_ref(self.types); let lhs_resolved = lhs.resolve_ref(self.types);
let rhs_resolved = rhs.resolve_ref(self.types); let rhs_resolved = rhs.resolve_ref(self.types);
let mut binops = self let binops = self
.types .types
.binop_types .binop_types
.iter() .iter()
.filter(|b| b.1.operator == op && b.1.return_ty == *ty) .filter(|b| b.1.operator == op && b.1.return_ty == *ty)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Sort binops by lhs and then rhs
binops.sort_by(|a, b| {
let lhs = a.1.hands.0.cmp(&b.1.hands.0);
let rhs = a.1.hands.1.cmp(&b.1.hands.1);
match lhs {
std::cmp::Ordering::Equal => rhs,
_ => lhs,
}
});
for binop in binops { for binop in binops {
if let (Ok(lhs_narrow), Ok(rhs_narrow)) = ( if let (Ok(lhs_narrow), Ok(rhs_narrow)) = (
lhs_resolved.narrow_into(&binop.1.hands.0), lhs_resolved.narrow_into(&binop.1.hands.0),
@ -498,17 +472,6 @@ impl<'outer> ScopeTypeRefs<'outer> {
} }
} }
} }
// Sort binops by lhs and then rhs
applying_binops.sort_by(|a, b| {
let lhs = a.hands.0.cmp(&b.hands.0);
let rhs = a.hands.1.cmp(&b.hands.1);
match lhs {
std::cmp::Ordering::Equal => rhs,
_ => lhs,
}
});
applying_binops applying_binops
} }
} }

View File

@ -6,17 +6,17 @@ use reid::{
mir::{self}, mir::{self},
parse_module, perform_all_passes, parse_module, perform_all_passes,
}; };
use reid_lib::{compile::CompileOutput, Context}; use reid_lib::Context;
use util::assert_err; use util::assert_err;
mod util; mod util;
fn test_compile(source: &str, name: &str) -> CompileOutput { fn test(source: &str, name: &str, expected_exit_code: Option<i32>) {
assert_err(assert_err(std::panic::catch_unwind(|| { assert_err(assert_err(std::panic::catch_unwind(|| {
let mut map = Default::default(); let mut map = Default::default();
let (id, tokens) = assert_err(parse_module(source, name, None, &mut map, None)); let (id, tokens) = assert_err(parse_module(source, name, &mut map));
let module = assert_err(assert_err(compile_module(id, tokens, &mut map, None, true)).map_err(|(_, e)| e)); let module = assert_err(compile_module(id, tokens, &mut map, None, true));
let mut mir_context = mir::Context::from(vec![module], Default::default()); let mut mir_context = mir::Context::from(vec![module], Default::default());
assert_err(perform_all_passes(&mut mir_context, &mut map)); assert_err(perform_all_passes(&mut mir_context, &mut map));
@ -24,14 +24,7 @@ fn test_compile(source: &str, name: &str) -> CompileOutput {
let codegen = assert_err(mir_context.codegen(&context)); let codegen = assert_err(mir_context.codegen(&context));
Ok::<_, ()>(codegen.compile(None, Vec::new()).output()) let output = codegen.compile(None, Vec::new()).output();
})))
}
fn test(source: &str, name: &str, expected_exit_code: Option<i32>) {
assert_err(assert_err(std::panic::catch_unwind(|| {
let output = test_compile(source, name);
let time = SystemTime::now(); let time = SystemTime::now();
let in_path = PathBuf::from(format!( let in_path = PathBuf::from(format!(
"/tmp/temp-{}.o", "/tmp/temp-{}.o",
@ -156,21 +149,6 @@ fn associated_functions() {
test( test(
include_str!("../../examples/associated_functions.reid"), include_str!("../../examples/associated_functions.reid"),
"test", "test",
Some(4), Some(32),
); );
} }
#[test]
fn mutable_inner_functions() {
test(include_str!("../../examples/mutable_inner.reid"), "test", Some(0));
}
#[test]
fn cpu_raytracer_compiles() {
test_compile(include_str!("../../examples/cpu_raytracer.reid"), "test");
}
#[test]
fn loop_edge_case_functions() {
test(include_str!("../../examples/loop_edge_case.reid"), "test", Some(0));
}