Compare commits
17 Commits
691c91504b
...
c699b67d75
Author | SHA1 | Date | |
---|---|---|---|
c699b67d75 | |||
ccb5741666 | |||
9fcf19383c | |||
59ecaa0d92 | |||
bb69ce4968 | |||
1a65b4085f | |||
c622d59c93 | |||
fe4e41c435 | |||
8be6ce1549 | |||
4de346e3c0 | |||
efeefe0bfe | |||
bd356f11db | |||
8b79959288 | |||
82758ae333 | |||
b723ff2d06 | |||
3a68154ae5 | |||
b9459a19bb |
@ -42,15 +42,20 @@ Currently missing big features (TODOs) are:
|
|||||||
- ~~Unary operators~~
|
- ~~Unary operators~~
|
||||||
- ~~Floats~~ (DONE)
|
- ~~Floats~~ (DONE)
|
||||||
- ~~Type casting~~ (DONE)
|
- ~~Type casting~~ (DONE)
|
||||||
- Built-in Int/Float division and modulo
|
- ~~Built-in Int/Float division and modulo~~
|
||||||
- Loops
|
- Loops
|
||||||
- Debug Information (PARTIALLY DONE)
|
- Debug Information (PARTIALLY DONE)
|
||||||
- Ability to specify types in literals and variable definitions
|
- Ability to specify types in literals and variable definitions
|
||||||
|
- Intrinsic functions
|
||||||
|
- Not-Unary
|
||||||
|
|
||||||
Big features that I want later but are not necessary:
|
Big features that I want later but are not necessary:
|
||||||
- Associated functions
|
- Associated functions
|
||||||
- User-defined binary operations
|
- User-defined binary operations
|
||||||
- Asymmetric binary operations (e.g. string + u32)
|
- Asymmetric binary operations (e.g. string + u32)
|
||||||
|
- Error handling
|
||||||
|
- Lexing & parsing of whitespace and comments as well
|
||||||
|
- LSP implementation
|
||||||
|
|
||||||
Smaller features:
|
Smaller features:
|
||||||
- Hex-numbers
|
- Hex-numbers
|
||||||
|
@ -1,30 +1,24 @@
|
|||||||
// Arithmetic, function calls and imports!
|
// Arithmetic, function calls and imports!
|
||||||
|
|
||||||
struct Test {
|
struct Test {
|
||||||
field: i32,
|
field: i32,
|
||||||
second: [u32; 4]
|
second: [u32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test() -> Test {
|
fn test() -> Test {
|
||||||
let value = Test {
|
let value = Test {
|
||||||
field: 5,
|
field: 5,
|
||||||
second: [6, 3, 4, 8],
|
second: [6, 3, 4, 8],
|
||||||
};
|
};
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> u32 {
|
fn main() -> u32 {
|
||||||
let mut value = test();
|
let mut value = test();
|
||||||
|
|
||||||
let mut a = &mut value;
|
let mut a = &mut value;
|
||||||
|
|
||||||
*a.second[2] = 15;
|
*a.second[2] = 5;
|
||||||
|
|
||||||
let b = 4;
|
return *a.second[2];
|
||||||
if value.field < b {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return value.second[2];
|
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,9 @@ fn other() -> i16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> u32 {
|
fn main() -> u32 {
|
||||||
let value = other() as u32;
|
|
||||||
let other_value = other() as f32;
|
|
||||||
let same_value = other() as i16;
|
|
||||||
|
|
||||||
let v = (allocate(4) as *u32);
|
let mut v = (allocate(4) as *u32);
|
||||||
|
v[0] = other() as u32;
|
||||||
|
|
||||||
return v[0];
|
return v[0];
|
||||||
}
|
}
|
||||||
|
6
examples/div_mod.reid
Normal file
6
examples/div_mod.reid
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Arithmetic, function calls and imports!
|
||||||
|
|
||||||
|
fn main() -> u16 {
|
||||||
|
|
||||||
|
return (50 / 5 + 52 % 5);
|
||||||
|
}
|
@ -10,7 +10,7 @@ fn main() -> i32 {
|
|||||||
|
|
||||||
add_char(&mut test, '!');
|
add_char(&mut test, '!');
|
||||||
set_char(&mut test, 'B', 0);
|
set_char(&mut test, 'B', 0);
|
||||||
add_num_to_str(&mut test, 7);
|
add_num_to_str(&mut test, 1234);
|
||||||
|
|
||||||
print(&test);
|
print(&test);
|
||||||
|
|
||||||
|
3
examples/ptr.reid
Normal file → Executable file
3
examples/ptr.reid
Normal file → Executable file
@ -1,8 +1,9 @@
|
|||||||
// Arithmetic, function calls and imports!
|
// Arithmetic, function calls and imports!
|
||||||
|
|
||||||
|
import std::allocate;
|
||||||
|
|
||||||
fn main() -> u8 {
|
fn main() -> u8 {
|
||||||
let mut ptr = malloc(4);
|
let mut ptr = allocate(4);
|
||||||
|
|
||||||
ptr[0] = 5;
|
ptr[0] = 5;
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
|
|
||||||
|
import std::from_str;
|
||||||
import std::print;
|
import std::print;
|
||||||
import std::int_div;
|
import std::int_div;
|
||||||
|
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
let hello = "hello world";
|
let hello = from_str("hello world");
|
||||||
|
|
||||||
print(hello);
|
print(&hello);
|
||||||
|
|
||||||
return int_div(15, 5).quotient;
|
return int_div(15, 5).quotient;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
fn foo() -> f32 { return 1.0; }
|
|
||||||
|
|
||||||
fn main() -> u8 {
|
|
||||||
let mut a = 0;
|
|
||||||
a = (foo() * 1.0) as u8;
|
|
||||||
return a;
|
|
||||||
}
|
|
153
graphics.reid
153
graphics.reid
@ -1,153 +0,0 @@
|
|||||||
struct StringBuffer {
|
|
||||||
buffer: [char; 64],
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SDL_Thing {} // TODO: replace with proper dummy structs now that we can cast
|
|
||||||
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) -> *SDL_Thing;
|
|
||||||
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_Thing, renderer_out: &mut *SDL_Thing) -> bool;
|
|
||||||
extern fn SDL_Delay(ms: u32);
|
|
||||||
extern fn SDL_SetRenderDrawColor(renderer: *SDL_Thing, r: u8, g: u8, b: u8, a: u8);
|
|
||||||
extern fn SDL_RenderClear(renderer: *SDL_Thing);
|
|
||||||
extern fn SDL_RenderPresent(renderer: *SDL_Thing);
|
|
||||||
extern fn SDL_HasEvent(event_type: u32) -> bool;
|
|
||||||
extern fn SDL_PumpEvents();
|
|
||||||
extern fn SDL_FlushEvents(min_type: u32, max_type: u32);
|
|
||||||
extern fn SDL_GetTicks() -> u64;
|
|
||||||
extern fn SDL_snprintf(text: &mut StringBuffer, maxlen: u64, fmt: *char, var: u64) -> i32;
|
|
||||||
extern fn SDL_SetWindowTitle(window: *SDL_Thing, title: &StringBuffer) -> bool;
|
|
||||||
extern fn SDL_CreateTexture(renderer: *SDL_Thing,
|
|
||||||
pixel_format: u32, texture_access: u32, width: u32, height: u32) -> *SDL_Thing;
|
|
||||||
extern fn SDL_RenderTexture(renderer: *SDL_Thing,
|
|
||||||
texture: *SDL_Thing, srcfrect: &SDL_FRect, dstfrect: &SDL_FRect) -> bool;
|
|
||||||
extern fn SDL_UpdateTexture(texture: *SDL_Thing, rect: &SDL_Rect, pixels: *u8, pitch: u32) -> bool;
|
|
||||||
extern fn SDL_Log(fmt: *char, string_var: *char);
|
|
||||||
extern fn SDL_GetError() -> *char;
|
|
||||||
extern fn SDL_GetWindowSize(window: *SDL_Thing, w: &mut i32, h: &mut i32) -> bool;
|
|
||||||
|
|
||||||
struct GameState {
|
|
||||||
renderer: *SDL_Thing,
|
|
||||||
window: *SDL_Thing,
|
|
||||||
render_texture: *SDL_Thing,
|
|
||||||
frame_counter: u64,
|
|
||||||
pixels: *u8,
|
|
||||||
pixels_w: u32,
|
|
||||||
pixels_h: 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_TEXTUREACCESS_STREAMING = 1;
|
|
||||||
|
|
||||||
let init_success = SDL_Init(SDL_INIT_VIDEO);
|
|
||||||
if init_success == false {
|
|
||||||
SDL_Log("SDL init failed: %s", SDL_GetError());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut window = placeholder_ptr();
|
|
||||||
let mut renderer = placeholder_ptr();
|
|
||||||
let gfx_init_success = SDL_CreateWindowAndRenderer(
|
|
||||||
"graphical reid program", 640, 480, SDL_WINDOW_RESIZABLE,
|
|
||||||
&mut window, &mut renderer
|
|
||||||
);
|
|
||||||
if gfx_init_success == false {
|
|
||||||
SDL_Log("SDL renderer and window creation failed: %s", SDL_GetError());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let width = 256;
|
|
||||||
let height = 256;
|
|
||||||
let render_texture = SDL_CreateTexture(renderer,
|
|
||||||
SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
|
||||||
|
|
||||||
let pixels_len = (width * height * 4) as u64;
|
|
||||||
let pixels = SDL_malloc(pixels_len) as *u8;
|
|
||||||
let mut game_state = GameState {
|
|
||||||
renderer: renderer,
|
|
||||||
window: window,
|
|
||||||
render_texture: render_texture,
|
|
||||||
frame_counter: 0,
|
|
||||||
pixels: pixels,
|
|
||||||
pixels_w: width,
|
|
||||||
pixels_h: height,
|
|
||||||
};
|
|
||||||
|
|
||||||
frame_loop(game_state);
|
|
||||||
|
|
||||||
// TODO: maybe clean up resources here but also it's a bit of a waste of energy
|
|
||||||
SDL_Quit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frame_loop(game_state: GameState) -> GameState {
|
|
||||||
SDL_PumpEvents();
|
|
||||||
if SDL_HasEvent(256) { // SDL_EVENT_QUIT
|
|
||||||
return game_state;
|
|
||||||
}
|
|
||||||
SDL_FlushEvents(0, 4294967296);
|
|
||||||
|
|
||||||
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;
|
|
||||||
draw_pixels(game_state.pixels, 0, 0, w, h, game_state.frame_counter);
|
|
||||||
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, 4 * w) == false {
|
|
||||||
SDL_Log("UpdateTexture error: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
let src = SDL_FRect { x: 0.0, y: 0.0, w: w as f32, h: h as f32 };
|
|
||||||
let dst = SDL_FRect { x: 0.0, y: 0.0, w: screen_width as f32, h: screen_height as f32 };
|
|
||||||
if SDL_RenderTexture(renderer, game_state.render_texture, &src, &dst) == false {
|
|
||||||
SDL_Log("RenderTexture error: %s", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
|
||||||
SDL_Delay(16);
|
|
||||||
|
|
||||||
game_state.frame_counter = game_state.frame_counter + 1;
|
|
||||||
let mut s = StringBuffer {};
|
|
||||||
SDL_snprintf(&mut s, 64, "graphical reid program frame %u", game_state.frame_counter);
|
|
||||||
SDL_SetWindowTitle(game_state.window, &s);
|
|
||||||
|
|
||||||
return frame_loop(game_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn placeholder_ptr() -> *SDL_Thing {
|
|
||||||
return SDL_malloc(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_pixels(pixels: *u8, x: u32, y: u32, w: u32, h: u32, frame_counter: u64) -> i32 {
|
|
||||||
if y >= h {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
let index = (x + y * w) * 4;
|
|
||||||
|
|
||||||
pixels[index + 0] = x as u8;
|
|
||||||
pixels[index + 1] = y as u8;
|
|
||||||
pixels[index + 2] = frame_counter as u8;
|
|
||||||
pixels[index + 3] = 255;
|
|
||||||
|
|
||||||
let mut new_x = x + 1;
|
|
||||||
let mut new_y = y;
|
|
||||||
if new_x >= w {
|
|
||||||
new_x = 0;
|
|
||||||
new_y = y + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_pixels(pixels, new_x, new_y, w, h, frame_counter);
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -16,8 +16,7 @@ BINARY="$(echo $1 | cut -d'.' -f1)"".out"
|
|||||||
|
|
||||||
echo $1
|
echo $1
|
||||||
|
|
||||||
make clean SRC=$1 ; make SRC=$1 && echo ""
|
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
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Block, BlockData, CustomTypeKind, FunctionData, Instr, InstructionData, ModuleData,
|
Block, BlockData, CompileResult, CustomTypeKind, ErrorKind, FunctionData, Instr,
|
||||||
NamedStruct, TerminatorKind, Type, TypeCategory, TypeData,
|
InstructionData, ModuleData, NamedStruct, TerminatorKind, Type, TypeCategory, TypeData,
|
||||||
debug_information::{
|
debug_information::{
|
||||||
DebugInformation, DebugLocationValue, DebugMetadataValue, DebugProgramValue,
|
DebugInformation, DebugLocationValue, DebugMetadataValue, DebugProgramValue,
|
||||||
InstructionDebugRecordData,
|
InstructionDebugRecordData,
|
||||||
@ -151,7 +151,7 @@ impl Builder {
|
|||||||
block_val: &BlockValue,
|
block_val: &BlockValue,
|
||||||
data: InstructionData,
|
data: InstructionData,
|
||||||
name: String,
|
name: String,
|
||||||
) -> Result<InstructionValue, ()> {
|
) -> CompileResult<InstructionValue> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut modules = self.modules.borrow_mut();
|
let mut modules = self.modules.borrow_mut();
|
||||||
let module = modules.get_unchecked_mut(block_val.0.0.0);
|
let module = modules.get_unchecked_mut(block_val.0.0.0);
|
||||||
@ -236,14 +236,14 @@ impl Builder {
|
|||||||
&self,
|
&self,
|
||||||
block: &BlockValue,
|
block: &BlockValue,
|
||||||
value: TerminatorKind,
|
value: TerminatorKind,
|
||||||
) -> Result<(), ()> {
|
) -> CompileResult<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut modules = self.modules.borrow_mut();
|
let mut modules = self.modules.borrow_mut();
|
||||||
let module = modules.get_unchecked_mut(block.0.0.0);
|
let module = modules.get_unchecked_mut(block.0.0.0);
|
||||||
let function = module.functions.get_unchecked_mut(block.0.1);
|
let function = module.functions.get_unchecked_mut(block.0.1);
|
||||||
let block = function.blocks.get_unchecked_mut(block.1);
|
let block = function.blocks.get_unchecked_mut(block.1);
|
||||||
if let Some(_) = &block.data.terminator {
|
if let Some(_) = &block.data.terminator {
|
||||||
Err(())
|
Err(ErrorKind::Null)
|
||||||
} else {
|
} else {
|
||||||
block.data.terminator = Some(value);
|
block.data.terminator = Some(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -255,14 +255,14 @@ impl Builder {
|
|||||||
&self,
|
&self,
|
||||||
block: &BlockValue,
|
block: &BlockValue,
|
||||||
location: DebugLocationValue,
|
location: DebugLocationValue,
|
||||||
) -> Result<(), ()> {
|
) -> CompileResult<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut modules = self.modules.borrow_mut();
|
let mut modules = self.modules.borrow_mut();
|
||||||
let module = modules.get_unchecked_mut(block.0.0.0);
|
let module = modules.get_unchecked_mut(block.0.0.0);
|
||||||
let function = module.functions.get_unchecked_mut(block.0.1);
|
let function = module.functions.get_unchecked_mut(block.0.1);
|
||||||
let block = function.blocks.get_unchecked_mut(block.1);
|
let block = function.blocks.get_unchecked_mut(block.1);
|
||||||
if let Some(_) = &block.data.terminator_location {
|
if let Some(_) = &block.data.terminator_location {
|
||||||
Err(())
|
Err(ErrorKind::Null)
|
||||||
} else {
|
} else {
|
||||||
block.data.terminator_location = Some(location);
|
block.data.terminator_location = Some(location);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -270,7 +270,7 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn delete_block(&self, block: &BlockValue) -> Result<(), ()> {
|
pub(crate) unsafe fn delete_block(&self, block: &BlockValue) -> CompileResult<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut modules = self.modules.borrow_mut();
|
let mut modules = self.modules.borrow_mut();
|
||||||
let module = modules.get_unchecked_mut(block.0.0.0);
|
let module = modules.get_unchecked_mut(block.0.0.0);
|
||||||
@ -349,7 +349,7 @@ impl Builder {
|
|||||||
self.modules.clone()
|
self.modules.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_instruction(&self, instruction: &InstructionValue) -> Result<(), ()> {
|
pub fn check_instruction(&self, instruction: &InstructionValue) -> CompileResult<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
match self.instr_data(&instruction).kind {
|
match self.instr_data(&instruction).kind {
|
||||||
Instr::Param(_) => Ok(()),
|
Instr::Param(_) => Ok(()),
|
||||||
@ -372,7 +372,7 @@ impl Builder {
|
|||||||
if t.comparable() || t.category() != TypeCategory::Integer {
|
if t.comparable() || t.category() != TypeCategory::Integer {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(()) // TODO error: Types not comparable
|
Err(ErrorKind::Null) // TODO error: Types not comparable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::FCmp(_, lhs, rhs) => {
|
Instr::FCmp(_, lhs, rhs) => {
|
||||||
@ -380,17 +380,17 @@ impl Builder {
|
|||||||
if t.comparable() || t.category() != TypeCategory::Real {
|
if t.comparable() || t.category() != TypeCategory::Real {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(()) // TODO error: Types not comparable
|
Err(ErrorKind::Null) // TODO error: Types not comparable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::FunctionCall(fun, params) => {
|
Instr::FunctionCall(fun, params) => {
|
||||||
let param_types = self.function_data(&fun).params;
|
let param_types = self.function_data(&fun).params;
|
||||||
if param_types.len() != params.len() {
|
if param_types.len() != params.len() {
|
||||||
return Err(()); // TODO error: invalid amount of params
|
return Err(ErrorKind::Null); // TODO error: invalid amount of params
|
||||||
}
|
}
|
||||||
for (a, b) in param_types.iter().zip(params) {
|
for (a, b) in param_types.iter().zip(params) {
|
||||||
if *a != b.get_type(&self)? {
|
if *a != b.get_type(&self)? {
|
||||||
return Err(()); // TODO error: params do not match
|
return Err(ErrorKind::Null); // TODO error: params do not match
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -403,7 +403,7 @@ impl Builder {
|
|||||||
// incoming values come from blocks that are added later
|
// incoming values come from blocks that are added later
|
||||||
// than the one where this one exists.
|
// than the one where this one exists.
|
||||||
|
|
||||||
let first = iter.next().ok_or(())?;
|
let first = iter.next().ok_or(ErrorKind::Null)?;
|
||||||
for item in iter {
|
for item in iter {
|
||||||
match_types(first, item, &self)?;
|
match_types(first, item, &self)?;
|
||||||
}
|
}
|
||||||
@ -416,10 +416,10 @@ impl Builder {
|
|||||||
if *ptr_ty_inner == load_ty {
|
if *ptr_ty_inner == load_ty {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(()) // TODO error: inner type mismatch
|
Err(ErrorKind::Null) // TODO error: inner type mismatch
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(()) // TODO error: not a pointer
|
Err(ErrorKind::Null) // TODO error: not a pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::Store(ptr, _) => {
|
Instr::Store(ptr, _) => {
|
||||||
@ -427,7 +427,7 @@ impl Builder {
|
|||||||
if let Type::Ptr(_) = ty {
|
if let Type::Ptr(_) = ty {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(()) // TODO error: not a pointer
|
Err(ErrorKind::Null) // TODO error: not a pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::ArrayAlloca(_, _) => Ok(()),
|
Instr::ArrayAlloca(_, _) => Ok(()),
|
||||||
@ -435,26 +435,27 @@ impl Builder {
|
|||||||
let ptr_ty = ptr_val.get_type(&self)?;
|
let ptr_ty = ptr_val.get_type(&self)?;
|
||||||
match ptr_ty {
|
match ptr_ty {
|
||||||
Type::Ptr(_) => Ok(()),
|
Type::Ptr(_) => Ok(()),
|
||||||
_ => Err(()),
|
_ => Err(ErrorKind::Null),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::GetStructElemPtr(ptr_val, idx) => {
|
Instr::GetStructElemPtr(ptr_val, idx) => {
|
||||||
let ptr_ty = ptr_val.get_type(&self)?;
|
let ptr_ty = ptr_val.get_type(&self)?;
|
||||||
|
dbg!(&ptr_ty);
|
||||||
if let Type::Ptr(ty) = ptr_ty {
|
if let Type::Ptr(ty) = ptr_ty {
|
||||||
if let Type::CustomType(val) = *ty {
|
if let Type::CustomType(val) = *ty {
|
||||||
match self.type_data(&val).kind {
|
match self.type_data(&val).kind {
|
||||||
CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => {
|
CustomTypeKind::NamedStruct(NamedStruct(_, fields)) => {
|
||||||
if fields.len() <= idx as usize {
|
if fields.len() <= idx as usize {
|
||||||
return Err(()); // TODO error: no such field
|
return Err(ErrorKind::Null); // TODO error: no such field
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(()) // TODO error: not a struct
|
Err(ErrorKind::Null) // TODO error: not a struct
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(()) // TODO error: not a pointer
|
Err(ErrorKind::Null) // TODO error: not a pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::ExtractValue(val, _) => {
|
Instr::ExtractValue(val, _) => {
|
||||||
@ -464,7 +465,7 @@ impl Builder {
|
|||||||
CustomTypeKind::NamedStruct(_) => Ok(()),
|
CustomTypeKind::NamedStruct(_) => Ok(()),
|
||||||
},
|
},
|
||||||
Type::Array(_, _) => Ok(()),
|
Type::Array(_, _) => Ok(()),
|
||||||
_ => Err(()),
|
_ => Err(ErrorKind::Null),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::Trunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
Instr::Trunc(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||||
@ -545,7 +546,7 @@ impl InstructionValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_type(&self, builder: &Builder) -> Result<Type, ()> {
|
pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult<Type> {
|
||||||
use Instr::*;
|
use Instr::*;
|
||||||
unsafe {
|
unsafe {
|
||||||
match &builder.instr_data(self).kind {
|
match &builder.instr_data(self).kind {
|
||||||
@ -554,7 +555,7 @@ impl InstructionValue {
|
|||||||
.params
|
.params
|
||||||
.get(*nth)
|
.get(*nth)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(()),
|
.ok_or(ErrorKind::Null),
|
||||||
Constant(c) => Ok(c.get_type()),
|
Constant(c) => Ok(c.get_type()),
|
||||||
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
|
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
FAdd(lhs, rhs) => match_types(lhs, rhs, &builder),
|
FAdd(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
@ -572,7 +573,10 @@ impl InstructionValue {
|
|||||||
ICmp(_, _, _) => Ok(Type::Bool),
|
ICmp(_, _, _) => Ok(Type::Bool),
|
||||||
FCmp(_, _, _) => Ok(Type::Bool),
|
FCmp(_, _, _) => Ok(Type::Bool),
|
||||||
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
|
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
|
||||||
Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)),
|
Phi(values) => values
|
||||||
|
.first()
|
||||||
|
.ok_or(ErrorKind::Null)
|
||||||
|
.and_then(|v| v.get_type(&builder)),
|
||||||
Alloca(ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
|
Alloca(ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
|
||||||
Load(_, ty) => Ok(ty.clone()),
|
Load(_, ty) => Ok(ty.clone()),
|
||||||
Store(_, value) => value.get_type(builder),
|
Store(_, value) => value.get_type(builder),
|
||||||
@ -614,7 +618,7 @@ impl InstructionValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Array(elem_ty, _) => *elem_ty.clone(),
|
Type::Array(elem_ty, _) => *elem_ty.clone(),
|
||||||
_ => return Err(()),
|
_ => return Err(ErrorKind::Null),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Trunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
Trunc(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||||
@ -633,9 +637,9 @@ impl InstructionValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cast_to(&self, builder: &Builder, ty: &Type) -> Result<Instr, ()> {
|
fn cast_to(&self, builder: &Builder, ty: &Type) -> CompileResult<Instr> {
|
||||||
self.get_type(builder)?
|
self.get_type(builder)?
|
||||||
.cast_instruction(*self, &ty)
|
.cast_instruction(*self, &ty)
|
||||||
.ok_or(())
|
.ok_or(ErrorKind::Null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,14 @@ mod fmt;
|
|||||||
mod pad_adapter;
|
mod pad_adapter;
|
||||||
mod util;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
builder: Builder,
|
builder: Builder,
|
||||||
@ -254,7 +262,7 @@ impl<'builder> Block<'builder> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: T,
|
name: T,
|
||||||
instruction: Instr,
|
instruction: Instr,
|
||||||
) -> Result<InstructionValue, ()> {
|
) -> CompileResult<InstructionValue> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.builder.add_instruction(
|
self.builder.add_instruction(
|
||||||
&self.value,
|
&self.value,
|
||||||
@ -268,7 +276,7 @@ impl<'builder> Block<'builder> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(&mut self, instruction: Instr) -> Result<InstructionValue, ()> {
|
pub fn build(&mut self, instruction: Instr) -> CompileResult<InstructionValue> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let name = instruction.default_name().to_owned();
|
let name = instruction.default_name().to_owned();
|
||||||
self.builder.add_instruction(
|
self.builder.add_instruction(
|
||||||
@ -297,16 +305,16 @@ impl<'builder> Block<'builder> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn terminate(&mut self, instruction: TerminatorKind) -> Result<(), ()> {
|
pub fn terminate(&mut self, instruction: TerminatorKind) -> CompileResult<()> {
|
||||||
unsafe { self.builder.terminate(&self.value, instruction) }
|
unsafe { self.builder.terminate(&self.value, instruction) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_terminator_location(&mut self, location: DebugLocationValue) -> Result<(), ()> {
|
pub fn set_terminator_location(&mut self, location: DebugLocationValue) -> CompileResult<()> {
|
||||||
unsafe { self.builder.set_terminator_location(&self.value, location) }
|
unsafe { self.builder.set_terminator_location(&self.value, location) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete block if it is unused. Return true if deleted, false if not.
|
/// Delete block if it is unused. Return true if deleted, false if not.
|
||||||
pub fn delete_if_unused(&mut self) -> Result<bool, ()> {
|
pub fn delete_if_unused(&mut self) -> CompileResult<bool> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if !self.builder.is_block_used(self.value()) {
|
if !self.builder.is_block_used(self.value()) {
|
||||||
self.builder.delete_block(&self.value)?;
|
self.builder.delete_block(&self.value)?;
|
||||||
@ -682,7 +690,7 @@ pub enum TypeCategory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TerminatorKind {
|
impl TerminatorKind {
|
||||||
pub(crate) fn get_type(&self, builder: &Builder) -> Result<Type, ()> {
|
pub(crate) fn get_type(&self, builder: &Builder) -> CompileResult<Type> {
|
||||||
use TerminatorKind::*;
|
use TerminatorKind::*;
|
||||||
match self {
|
match self {
|
||||||
Ret(instr_val) => instr_val.get_type(builder),
|
Ret(instr_val) => instr_val.get_type(builder),
|
||||||
|
@ -14,7 +14,7 @@ use llvm_sys::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Type,
|
CompileResult, ErrorKind, Type,
|
||||||
builder::{Builder, InstructionValue},
|
builder::{Builder, InstructionValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,12 +117,16 @@ pub fn match_types(
|
|||||||
lhs: &InstructionValue,
|
lhs: &InstructionValue,
|
||||||
rhs: &InstructionValue,
|
rhs: &InstructionValue,
|
||||||
builder: &Builder,
|
builder: &Builder,
|
||||||
) -> Result<Type, ()> {
|
) -> CompileResult<Type> {
|
||||||
let lhs_type = lhs.get_type(&builder);
|
let lhs_type = lhs.get_type(&builder);
|
||||||
let rhs_type = rhs.get_type(&builder);
|
let rhs_type = rhs.get_type(&builder);
|
||||||
if let (Ok(lhs_t), Ok(rhs_t)) = (lhs_type, rhs_type) {
|
if let (Ok(lhs_t), Ok(rhs_t)) = (lhs_type, rhs_type) {
|
||||||
if lhs_t == rhs_t { Ok(lhs_t) } else { Err(()) }
|
if lhs_t == rhs_t {
|
||||||
|
Ok(lhs_t)
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::Null)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(ErrorKind::Null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
use std::{env, fs, path::PathBuf};
|
use std::{env, fs, path::PathBuf};
|
||||||
|
|
||||||
use reid::{compile_simple, CustomIRs};
|
use reid::{compile_simple, ld::LDRunner, CustomIRs};
|
||||||
use reid_lib::compile::CompileOutput;
|
use reid_lib::compile::CompileOutput;
|
||||||
|
|
||||||
fn main() -> Result<(), std::io::Error> {
|
fn main() -> Result<(), std::io::Error> {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if let Some(filename) = args.get(1) {
|
let mut iter = args.into_iter().skip(1);
|
||||||
|
if let Some(filename) = iter.next() {
|
||||||
|
let mut libraries = Vec::new();
|
||||||
|
while let Some(libname) = iter.next() {
|
||||||
|
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");
|
||||||
@ -17,6 +24,7 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
let before = std::time::SystemTime::now();
|
let before = std::time::SystemTime::now();
|
||||||
|
|
||||||
let text = fs::read_to_string(&path)?;
|
let text = fs::read_to_string(&path)?;
|
||||||
|
|
||||||
match compile_simple(&text, PathBuf::from(&path)) {
|
match compile_simple(&text, PathBuf::from(&path)) {
|
||||||
Ok((
|
Ok((
|
||||||
CompileOutput {
|
CompileOutput {
|
||||||
@ -45,6 +53,15 @@ fn main() -> Result<(), std::io::Error> {
|
|||||||
"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.
|
||||||
);
|
);
|
||||||
|
|
||||||
|
println!("Linking {:?}", &object_path);
|
||||||
|
|
||||||
|
let linker = std::env::var("LD").unwrap_or("ld".to_owned());
|
||||||
|
let mut linker = LDRunner::from_command(&linker).with_library("c");
|
||||||
|
for library in libraries {
|
||||||
|
linker = linker.with_library(&library);
|
||||||
|
}
|
||||||
|
linker.invoke(&object_path, &object_path.with_extension("out"));
|
||||||
}
|
}
|
||||||
Err(e) => panic!("{}", e),
|
Err(e) => panic!("{}", e),
|
||||||
};
|
};
|
||||||
|
@ -93,14 +93,36 @@ fn str_length(string: *char, position: u32) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_num_to_str(string: &mut String, num: u64) {
|
pub fn add_num_to_str(string: &mut String, num: u64) {
|
||||||
if num == 0 { add_char(string, '0'); }
|
if num > 10 {
|
||||||
else if num == 1 { add_char(string, '1'); }
|
add_num_to_str(string, num / 10)
|
||||||
else if num == 2 { add_char(string, '2'); }
|
}
|
||||||
else if num == 3 { add_char(string, '3'); }
|
let rem = num % 10;
|
||||||
else if num == 4 { add_char(string, '4'); }
|
|
||||||
else if num == 5 { add_char(string, '5'); }
|
if rem == 0 { add_char(string, '0'); }
|
||||||
else if num == 6 { add_char(string, '6'); }
|
else if rem == 1 { add_char(string, '1'); }
|
||||||
else if num == 7 { add_char(string, '7'); }
|
else if rem == 2 { add_char(string, '2'); }
|
||||||
else if num == 8 { add_char(string, '8'); }
|
else if rem == 3 { add_char(string, '3'); }
|
||||||
else if num == 9 { add_char(string, '9'); }
|
else if rem == 4 { add_char(string, '4'); }
|
||||||
|
else if rem == 5 { add_char(string, '5'); }
|
||||||
|
else if rem == 6 { add_char(string, '6'); }
|
||||||
|
else if rem == 7 { add_char(string, '7'); }
|
||||||
|
else if rem == 8 { add_char(string, '8'); }
|
||||||
|
else if rem == 9 { add_char(string, '9'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clamp(min: f32, max: f32, value: f32) -> f32 {
|
||||||
|
if value > max {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
if value < min {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn abs(f: f32) -> f32 {
|
||||||
|
if f < 0.0 {
|
||||||
|
return f * (0.0 - 1.0);
|
||||||
|
}
|
||||||
|
return f;
|
||||||
}
|
}
|
@ -81,6 +81,8 @@ pub enum BinaryOperator {
|
|||||||
Add,
|
Add,
|
||||||
Minus,
|
Minus,
|
||||||
Mult,
|
Mult,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
|
||||||
And,
|
And,
|
||||||
LT,
|
LT,
|
||||||
@ -95,9 +97,11 @@ impl BinaryOperator {
|
|||||||
pub fn get_precedence(&self) -> i8 {
|
pub fn get_precedence(&self) -> i8 {
|
||||||
use BinaryOperator::*;
|
use BinaryOperator::*;
|
||||||
match &self {
|
match &self {
|
||||||
|
Minus => 5,
|
||||||
Add => 10,
|
Add => 10,
|
||||||
Minus => 10,
|
Mult => 15,
|
||||||
Mult => 20,
|
Div => 20,
|
||||||
|
Mod => 20,
|
||||||
And => 100,
|
And => 100,
|
||||||
LT => 100,
|
LT => 100,
|
||||||
LE => 100,
|
LE => 100,
|
||||||
|
@ -350,6 +350,8 @@ impl Parse for BinaryOperator {
|
|||||||
(Some(Token::Plus), _) => BinaryOperator::Add,
|
(Some(Token::Plus), _) => BinaryOperator::Add,
|
||||||
(Some(Token::Minus), _) => BinaryOperator::Minus,
|
(Some(Token::Minus), _) => BinaryOperator::Minus,
|
||||||
(Some(Token::Star), _) => BinaryOperator::Mult,
|
(Some(Token::Star), _) => BinaryOperator::Mult,
|
||||||
|
(Some(Token::Slash), _) => BinaryOperator::Div,
|
||||||
|
(Some(Token::Percent), _) => BinaryOperator::Mod,
|
||||||
(_, _) => Err(stream.expected_err("expected operator")?)?,
|
(_, _) => Err(stream.expected_err("expected operator")?)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ impl ast::Module {
|
|||||||
block.into_mir(module_id),
|
block.into_mir(module_id),
|
||||||
(*range).as_meta(module_id),
|
(*range).as_meta(module_id),
|
||||||
),
|
),
|
||||||
|
source: module_id,
|
||||||
};
|
};
|
||||||
functions.push(def);
|
functions.push(def);
|
||||||
}
|
}
|
||||||
@ -70,6 +71,7 @@ impl ast::Module {
|
|||||||
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
|
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
|
||||||
.collect(),
|
.collect(),
|
||||||
kind: mir::FunctionDefinitionKind::Extern(false),
|
kind: mir::FunctionDefinitionKind::Extern(false),
|
||||||
|
source: module_id,
|
||||||
};
|
};
|
||||||
functions.push(def);
|
functions.push(def);
|
||||||
}
|
}
|
||||||
@ -286,6 +288,8 @@ impl ast::BinaryOperator {
|
|||||||
ast::BinaryOperator::Minus => mir::BinaryOperator::Minus,
|
ast::BinaryOperator::Minus => mir::BinaryOperator::Minus,
|
||||||
ast::BinaryOperator::Mult => mir::BinaryOperator::Mult,
|
ast::BinaryOperator::Mult => mir::BinaryOperator::Mult,
|
||||||
ast::BinaryOperator::And => mir::BinaryOperator::And,
|
ast::BinaryOperator::And => mir::BinaryOperator::And,
|
||||||
|
ast::BinaryOperator::Div => mir::BinaryOperator::Div,
|
||||||
|
ast::BinaryOperator::Mod => mir::BinaryOperator::Mod,
|
||||||
ast::BinaryOperator::LT => mir::BinaryOperator::Cmp(mir::CmpOperator::LT),
|
ast::BinaryOperator::LT => mir::BinaryOperator::Cmp(mir::CmpOperator::LT),
|
||||||
ast::BinaryOperator::LE => mir::BinaryOperator::Cmp(mir::CmpOperator::LE),
|
ast::BinaryOperator::LE => mir::BinaryOperator::Cmp(mir::CmpOperator::LE),
|
||||||
ast::BinaryOperator::GT => mir::BinaryOperator::Cmp(mir::CmpOperator::GT),
|
ast::BinaryOperator::GT => mir::BinaryOperator::Cmp(mir::CmpOperator::GT),
|
||||||
|
@ -20,8 +20,15 @@ use crate::{
|
|||||||
self, implement::TypeCategory, CustomTypeKey, Metadata, NamedVariableRef, SourceModuleId,
|
self, implement::TypeCategory, CustomTypeKey, Metadata, NamedVariableRef, SourceModuleId,
|
||||||
StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral,
|
StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral,
|
||||||
},
|
},
|
||||||
|
util::try_all,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub enum ErrorKind {
|
||||||
|
#[error("NULL error, should never occur!")]
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
/// Context that contains all of the given modules as complete codegenerated
|
/// Context that contains all of the given modules as complete codegenerated
|
||||||
/// LLIR that can then be finally compiled into LLVM IR.
|
/// LLIR that can then be finally compiled into LLVM IR.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -39,16 +46,16 @@ impl<'ctx> CodegenContext<'ctx> {
|
|||||||
|
|
||||||
impl mir::Context {
|
impl mir::Context {
|
||||||
/// Compile MIR [`Context`] into [`CodegenContext`] containing LLIR.
|
/// Compile MIR [`Context`] into [`CodegenContext`] containing LLIR.
|
||||||
pub fn codegen<'ctx>(&self, context: &'ctx Context) -> CodegenContext<'ctx> {
|
pub fn codegen<'ctx>(&self, context: &'ctx Context) -> Result<CodegenContext<'ctx>, ErrorKind> {
|
||||||
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 {
|
for module in &modules_sorted {
|
||||||
let codegen = module.codegen(context, modules.clone());
|
let codegen = module.codegen(context, modules.clone())?;
|
||||||
modules.insert(module.module_id, codegen);
|
modules.insert(module.module_id, codegen);
|
||||||
}
|
}
|
||||||
CodegenContext { context }
|
Ok(CodegenContext { context })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +201,7 @@ impl mir::Module {
|
|||||||
&'ctx self,
|
&'ctx self,
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
modules: HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
|
modules: HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
|
||||||
) -> ModuleCodegen<'ctx> {
|
) -> 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;
|
||||||
|
|
||||||
@ -430,7 +437,7 @@ impl mir::Module {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let state = State::default();
|
let state = State::default();
|
||||||
if let Some(ret) = block.codegen(&mut scope, &state) {
|
if let Some(ret) = block.codegen(&mut 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() {
|
||||||
@ -451,7 +458,7 @@ impl mir::Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleCodegen { module }
|
Ok(ModuleCodegen { module })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,9 +467,9 @@ impl mir::Block {
|
|||||||
&self,
|
&self,
|
||||||
mut scope: &mut Scope<'ctx, 'a>,
|
mut scope: &mut Scope<'ctx, 'a>,
|
||||||
state: &State,
|
state: &State,
|
||||||
) -> Option<StackValue> {
|
) -> Result<Option<StackValue>, ErrorKind> {
|
||||||
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 {
|
||||||
let location = stmt.1.into_debug(scope.tokens, debug.scope).unwrap();
|
let location = stmt.1.into_debug(scope.tokens, debug.scope).unwrap();
|
||||||
let loc_val = debug.info.location(&debug.scope, location);
|
let loc_val = debug.info.location(&debug.scope, location);
|
||||||
@ -472,22 +479,30 @@ impl mir::Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some((kind, expr)) = &self.return_expression {
|
if let Some((kind, expr)) = &self.return_expression {
|
||||||
let ret = expr.codegen(&mut scope, &mut state.load(true));
|
let ret = expr.codegen(&mut scope, &mut state.load(true))?;
|
||||||
match kind {
|
match kind {
|
||||||
mir::ReturnKind::Hard => {
|
mir::ReturnKind::Hard => {
|
||||||
scope.block.terminate(Term::Ret(ret?.instr())).unwrap();
|
if let Some(ret) = ret {
|
||||||
None
|
scope.block.terminate(Term::Ret(ret.instr())).unwrap();
|
||||||
|
} else {
|
||||||
|
scope.block.terminate(Term::RetVoid).unwrap();
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
mir::ReturnKind::Soft => ret,
|
mir::ReturnKind::Soft => Ok(ret),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mir::Statement {
|
impl mir::Statement {
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Option<StackValue> {
|
fn codegen<'ctx, 'a>(
|
||||||
|
&self,
|
||||||
|
scope: &mut Scope<'ctx, 'a>,
|
||||||
|
state: &State,
|
||||||
|
) -> Result<Option<StackValue>, ErrorKind> {
|
||||||
let location = scope.debug.clone().map(|d| {
|
let location = scope.debug.clone().map(|d| {
|
||||||
let location = self.1.into_debug(scope.tokens, d.scope).unwrap();
|
let location = self.1.into_debug(scope.tokens, d.scope).unwrap();
|
||||||
d.info.location(&d.scope, location)
|
d.info.location(&d.scope, location)
|
||||||
@ -495,7 +510,7 @@ impl mir::Statement {
|
|||||||
|
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
mir::StmtKind::Let(NamedVariableRef(ty, name, _), 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
|
||||||
.block
|
.block
|
||||||
@ -545,14 +560,17 @@ impl mir::Statement {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
mir::StmtKind::Set(lhs, rhs) => {
|
mir::StmtKind::Set(lhs, rhs) => {
|
||||||
let lhs_value = lhs
|
let lhs_value = lhs
|
||||||
.codegen(scope, &state.load(false))
|
.codegen(scope, &state.load(false))?
|
||||||
.expect("non-returning LHS snuck into codegen!");
|
.expect("non-returning LHS snuck into codegen!");
|
||||||
|
|
||||||
let rhs_value = rhs.codegen(scope, state)?;
|
let rhs_value = rhs.codegen(scope, state)?;
|
||||||
|
let Some(rhs_value) = rhs_value else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
let backing_var = if let Some(var) = lhs.backing_var() {
|
let backing_var = if let Some(var) = lhs.backing_var() {
|
||||||
&format!("store.{}", var.1)
|
&format!("store.{}", var.1)
|
||||||
@ -576,7 +594,7 @@ impl mir::Statement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
mir::StmtKind::Import(_) => todo!(),
|
mir::StmtKind::Import(_) => todo!(),
|
||||||
mir::StmtKind::Expression(expression) => expression.codegen(scope, state),
|
mir::StmtKind::Expression(expression) => expression.codegen(scope, state),
|
||||||
@ -585,7 +603,11 @@ impl mir::Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl mir::Expression {
|
impl mir::Expression {
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Option<StackValue> {
|
fn codegen<'ctx, 'a>(
|
||||||
|
&self,
|
||||||
|
scope: &mut Scope<'ctx, 'a>,
|
||||||
|
state: &State,
|
||||||
|
) -> Result<Option<StackValue>, ErrorKind> {
|
||||||
let location = if let Some(debug) = &scope.debug {
|
let location = if let Some(debug) = &scope.debug {
|
||||||
Some(debug.info.location(
|
Some(debug.info.location(
|
||||||
&debug.scope,
|
&debug.scope,
|
||||||
@ -634,11 +656,11 @@ impl mir::Expression {
|
|||||||
)),
|
)),
|
||||||
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
||||||
let lhs = lhs_exp
|
let lhs = lhs_exp
|
||||||
.codegen(scope, state)
|
.codegen(scope, state)?
|
||||||
.expect("lhs has no return value")
|
.expect("lhs has no return value")
|
||||||
.instr();
|
.instr();
|
||||||
let rhs = rhs_exp
|
let rhs = rhs_exp
|
||||||
.codegen(scope, state)
|
.codegen(scope, state)?
|
||||||
.expect("rhs has no return value")
|
.expect("rhs has no return value")
|
||||||
.instr();
|
.instr();
|
||||||
let lhs_type = lhs_exp
|
let lhs_type = lhs_exp
|
||||||
@ -659,9 +681,57 @@ impl mir::Expression {
|
|||||||
(mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs),
|
(mir::BinaryOperator::And, _, _) => Instr::And(lhs, rhs),
|
||||||
(mir::BinaryOperator::Cmp(i), _, false) => Instr::ICmp(i.predicate(), lhs, rhs),
|
(mir::BinaryOperator::Cmp(i), _, false) => Instr::ICmp(i.predicate(), lhs, rhs),
|
||||||
(mir::BinaryOperator::Cmp(i), _, true) => Instr::FCmp(i.predicate(), lhs, rhs),
|
(mir::BinaryOperator::Cmp(i), _, true) => Instr::FCmp(i.predicate(), lhs, rhs),
|
||||||
|
(mir::BinaryOperator::Div, false, false) => Instr::UDiv(lhs, rhs),
|
||||||
|
(mir::BinaryOperator::Div, true, false) => Instr::SDiv(lhs, rhs),
|
||||||
|
(mir::BinaryOperator::Div, _, true) => Instr::FDiv(lhs, rhs),
|
||||||
|
(mir::BinaryOperator::Mod, false, false) => {
|
||||||
|
let div = scope
|
||||||
|
.block
|
||||||
|
.build(Instr::UDiv(lhs, rhs))
|
||||||
|
.unwrap()
|
||||||
|
.maybe_location(&mut scope.block, location);
|
||||||
|
let mul = scope
|
||||||
|
.block
|
||||||
|
.build(Instr::Mul(rhs, div))
|
||||||
|
.unwrap()
|
||||||
|
.maybe_location(&mut scope.block, location);
|
||||||
|
Instr::Sub(lhs, mul)
|
||||||
|
}
|
||||||
|
(mir::BinaryOperator::Mod, true, false) => {
|
||||||
|
let div = scope
|
||||||
|
.block
|
||||||
|
.build(Instr::SDiv(lhs, rhs))
|
||||||
|
.unwrap()
|
||||||
|
.maybe_location(&mut scope.block, location);
|
||||||
|
let mul = scope
|
||||||
|
.block
|
||||||
|
.build(Instr::Mul(rhs, div))
|
||||||
|
.unwrap()
|
||||||
|
.maybe_location(&mut scope.block, location);
|
||||||
|
Instr::Sub(lhs, mul)
|
||||||
|
}
|
||||||
|
(mir::BinaryOperator::Mod, _, true) => {
|
||||||
|
let div = scope
|
||||||
|
.block
|
||||||
|
.build(Instr::FDiv(lhs, rhs))
|
||||||
|
.unwrap()
|
||||||
|
.maybe_location(&mut scope.block, location);
|
||||||
|
let mul = scope
|
||||||
|
.block
|
||||||
|
.build(Instr::Mul(rhs, div))
|
||||||
|
.unwrap()
|
||||||
|
.maybe_location(&mut scope.block, location);
|
||||||
|
Instr::Sub(lhs, mul)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Some(StackValue(
|
Some(StackValue(
|
||||||
StackValueKind::Immutable(scope.block.build(instr).unwrap()),
|
StackValueKind::Immutable(
|
||||||
|
scope
|
||||||
|
.block
|
||||||
|
.build(instr)
|
||||||
|
.unwrap()
|
||||||
|
.maybe_location(&mut scope.block, location),
|
||||||
|
),
|
||||||
lhs_type,
|
lhs_type,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -673,11 +743,17 @@ impl mir::Expression {
|
|||||||
|
|
||||||
let ret_type = ret_type_kind.get_type(scope.type_values, scope.types);
|
let ret_type = ret_type_kind.get_type(scope.type_values, scope.types);
|
||||||
|
|
||||||
let params = call
|
let params = try_all(
|
||||||
.parameters
|
call.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| e.codegen(scope, state).unwrap())
|
.map(|e| e.codegen(scope, state))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
.map_err(|e| e.first().cloned().unwrap())?
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| v.unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let param_instrs = params.iter().map(|e| e.instr()).collect();
|
let param_instrs = params.iter().map(|e| e.instr()).collect();
|
||||||
let callee = scope
|
let callee = scope
|
||||||
.functions
|
.functions
|
||||||
@ -734,13 +810,13 @@ impl mir::Expression {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state),
|
mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state)?,
|
||||||
mir::ExprKind::Block(block) => {
|
mir::ExprKind::Block(block) => {
|
||||||
let inner = scope.function.ir.block("inner");
|
let inner = scope.function.ir.block("inner");
|
||||||
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) {
|
let ret = if let Some(ret) = block.codegen(&mut inner_scope, state)? {
|
||||||
Some(ret)
|
Some(ret)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -752,18 +828,13 @@ impl mir::Expression {
|
|||||||
}
|
}
|
||||||
mir::ExprKind::Indexed(expression, val_t, idx_expr) => {
|
mir::ExprKind::Indexed(expression, val_t, idx_expr) => {
|
||||||
let StackValue(kind, ty) = expression
|
let StackValue(kind, ty) = expression
|
||||||
.codegen(scope, &state.load(false))
|
.codegen(scope, &state.load(false))?
|
||||||
.expect("array returned none!");
|
.expect("array returned none!");
|
||||||
let idx = idx_expr
|
let idx = idx_expr
|
||||||
.codegen(scope, &state.load(true))
|
.codegen(scope, &state.load(true))?
|
||||||
.expect("index returned none!")
|
.expect("index returned none!")
|
||||||
.instr();
|
.instr();
|
||||||
|
|
||||||
let first = scope
|
|
||||||
.block
|
|
||||||
.build_named("array.zero", Instr::Constant(ConstValue::U32(0)))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let TypeKind::CodegenPtr(inner) = ty else {
|
let TypeKind::CodegenPtr(inner) = ty else {
|
||||||
panic!();
|
panic!();
|
||||||
};
|
};
|
||||||
@ -772,7 +843,7 @@ impl mir::Expression {
|
|||||||
let loaded = scope
|
let loaded = scope
|
||||||
.block
|
.block
|
||||||
.build_named(
|
.build_named(
|
||||||
"array.load",
|
"load",
|
||||||
Instr::Load(
|
Instr::Load(
|
||||||
kind.instr(),
|
kind.instr(),
|
||||||
inner.get_type(scope.type_values, scope.types),
|
inner.get_type(scope.type_values, scope.types),
|
||||||
@ -782,15 +853,36 @@ impl mir::Expression {
|
|||||||
(
|
(
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
.build_named(format!("array.gep"), Instr::GetElemPtr(loaded, vec![idx]))
|
.build_named(format!("gep"), Instr::GetElemPtr(loaded, vec![idx]))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.maybe_location(&mut scope.block, location),
|
.maybe_location(&mut scope.block, location),
|
||||||
*further_inner,
|
*further_inner,
|
||||||
)
|
)
|
||||||
|
} else if let TypeKind::CodegenPtr(further_inner) = *inner.clone() {
|
||||||
|
let TypeKind::Array(_, _) = *further_inner else {
|
||||||
|
panic!();
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
scope
|
||||||
|
.block
|
||||||
|
.build_named(
|
||||||
|
format!("array.gep"),
|
||||||
|
Instr::GetElemPtr(kind.instr(), vec![idx]),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.maybe_location(&mut scope.block, location),
|
||||||
|
val_t.clone(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let TypeKind::Array(_, _) = *inner else {
|
let TypeKind::Array(_, _) = *inner else {
|
||||||
panic!();
|
panic!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let first = scope
|
||||||
|
.block
|
||||||
|
.build_named("array.zero", Instr::Constant(ConstValue::U32(0)))
|
||||||
|
.unwrap();
|
||||||
(
|
(
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
@ -829,10 +921,17 @@ impl mir::Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::ExprKind::Array(expressions) => {
|
mir::ExprKind::Array(expressions) => {
|
||||||
let stack_value_list = expressions
|
let stack_value_list: Vec<_> = try_all(
|
||||||
.iter()
|
expressions
|
||||||
.map(|e| e.codegen(scope, state).unwrap())
|
.iter()
|
||||||
.collect::<Vec<_>>();
|
.map(|e| e.codegen(scope, state))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
.map_err(|e| e.first().cloned().unwrap())?
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| v.unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
let instr_list = stack_value_list
|
let instr_list = stack_value_list
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.instr())
|
.map(|s| s.instr())
|
||||||
@ -896,11 +995,12 @@ impl mir::Expression {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
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 {
|
||||||
panic!("tried accessing non-pointer");
|
panic!("tried accessing non-pointer");
|
||||||
};
|
};
|
||||||
|
dbg!(&inner);
|
||||||
let TypeKind::CustomType(key) = *inner.clone() else {
|
let TypeKind::CustomType(key) = *inner.clone() else {
|
||||||
panic!("tried accessing non-custom-type");
|
panic!("tried accessing non-custom-type");
|
||||||
};
|
};
|
||||||
@ -948,7 +1048,12 @@ impl mir::Expression {
|
|||||||
}
|
}
|
||||||
mir::ExprKind::Struct(name, items) => {
|
mir::ExprKind::Struct(name, items) => {
|
||||||
let type_key = CustomTypeKey(name.clone(), scope.module_id);
|
let type_key = CustomTypeKey(name.clone(), scope.module_id);
|
||||||
let struct_ty = Type::CustomType(*scope.type_values.get(&type_key)?);
|
let struct_ty = Type::CustomType({
|
||||||
|
let Some(a) = scope.type_values.get(&type_key) else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
*a
|
||||||
|
});
|
||||||
|
|
||||||
let load_n = format!("{}.load", name);
|
let load_n = format!("{}.load", name);
|
||||||
|
|
||||||
@ -967,7 +1072,7 @@ impl mir::Expression {
|
|||||||
.build_named(gep_n, Instr::GetStructElemPtr(struct_ptr, i as u32))
|
.build_named(gep_n, Instr::GetStructElemPtr(struct_ptr, i as u32))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.maybe_location(&mut scope.block, location);
|
.maybe_location(&mut scope.block, location);
|
||||||
if let Some(val) = exp.codegen(scope, state) {
|
if let Some(val) = exp.codegen(scope, state)? {
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
.build_named(store_n, Instr::Store(elem_ptr, val.instr()))
|
.build_named(store_n, Instr::Store(elem_ptr, val.instr()))
|
||||||
@ -992,9 +1097,14 @@ impl mir::Expression {
|
|||||||
.stack_values
|
.stack_values
|
||||||
.get(&varref.1)
|
.get(&varref.1)
|
||||||
.expect("Variable reference not found?!");
|
.expect("Variable reference not found?!");
|
||||||
|
|
||||||
|
let TypeKind::CodegenPtr(ptr_inner) = &v.1 else {
|
||||||
|
panic!();
|
||||||
|
};
|
||||||
|
|
||||||
Some(StackValue(
|
Some(StackValue(
|
||||||
StackValueKind::mutable(*mutable, v.0.instr()),
|
StackValueKind::mutable(*mutable, v.0.instr()),
|
||||||
v.1.clone(),
|
TypeKind::Borrow(Box::new(*ptr_inner.clone()), *mutable),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
mir::ExprKind::Deref(varref) => {
|
mir::ExprKind::Deref(varref) => {
|
||||||
@ -1053,6 +1163,7 @@ impl mir::Expression {
|
|||||||
}
|
}
|
||||||
mir::ExprKind::CastTo(expression, type_kind) => {
|
mir::ExprKind::CastTo(expression, type_kind) => {
|
||||||
let val = expression.codegen(scope, state)?;
|
let val = expression.codegen(scope, state)?;
|
||||||
|
let Some(val) = val else { return Ok(None) };
|
||||||
|
|
||||||
if val.1 == *type_kind {
|
if val.1 == *type_kind {
|
||||||
Some(val)
|
Some(val)
|
||||||
@ -1113,13 +1224,17 @@ impl mir::Expression {
|
|||||||
if let Some(value) = &value {
|
if let Some(value) = &value {
|
||||||
value.instr().maybe_location(&mut scope.block, location);
|
value.instr().maybe_location(&mut scope.block, location);
|
||||||
}
|
}
|
||||||
value
|
Ok(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mir::IfExpression {
|
impl mir::IfExpression {
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Option<StackValue> {
|
fn codegen<'ctx, 'a>(
|
||||||
let condition = self.0.codegen(scope, state).unwrap();
|
&self,
|
||||||
|
scope: &mut Scope<'ctx, 'a>,
|
||||||
|
state: &State,
|
||||||
|
) -> Result<Option<StackValue>, ErrorKind> {
|
||||||
|
let condition = self.0.codegen(scope, state)?.unwrap();
|
||||||
|
|
||||||
// Create blocks
|
// Create blocks
|
||||||
let mut then_b = scope.function.ir.block("then");
|
let mut then_b = scope.function.ir.block("then");
|
||||||
@ -1151,7 +1266,7 @@ impl mir::IfExpression {
|
|||||||
|
|
||||||
// Generate then-block content
|
// Generate then-block content
|
||||||
let mut then_scope = scope.with_block(then_b);
|
let mut then_scope = scope.with_block(then_b);
|
||||||
let then_res = self.1.codegen(&mut then_scope, state);
|
let then_res = self.1.codegen(&mut then_scope, state)?;
|
||||||
then_scope.block.terminate(Term::Br(after_bb)).ok();
|
then_scope.block.terminate(Term::Br(after_bb)).ok();
|
||||||
|
|
||||||
let else_res = if let Some(else_expr) = self.2.as_ref() {
|
let else_res = if let Some(else_expr) = self.2.as_ref() {
|
||||||
@ -1162,7 +1277,7 @@ impl mir::IfExpression {
|
|||||||
.terminate(Term::CondBr(condition.instr(), then_bb, else_bb))
|
.terminate(Term::CondBr(condition.instr(), then_bb, else_bb))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let opt = else_expr.codegen(&mut else_scope, state);
|
let opt = else_expr.codegen(&mut else_scope, state)?;
|
||||||
|
|
||||||
else_scope.block.terminate(Term::Br(after_bb)).ok();
|
else_scope.block.terminate(Term::Br(after_bb)).ok();
|
||||||
|
|
||||||
@ -1184,7 +1299,7 @@ impl mir::IfExpression {
|
|||||||
scope.swap_block(after_b);
|
scope.swap_block(after_b);
|
||||||
|
|
||||||
if then_res.is_none() && else_res.is_none() {
|
if then_res.is_none() && else_res.is_none() {
|
||||||
None
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
let mut incoming = Vec::from(then_res.as_slice());
|
let mut incoming = Vec::from(then_res.as_slice());
|
||||||
incoming.extend(else_res.clone());
|
incoming.extend(else_res.clone());
|
||||||
@ -1212,7 +1327,7 @@ impl mir::IfExpression {
|
|||||||
(Mutable(_), Mutable(_)) => StackValue(Mutable(instr), lhs_val.1),
|
(Mutable(_), Mutable(_)) => StackValue(Mutable(instr), lhs_val.1),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Some(value)
|
Ok(Some(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
codegen,
|
||||||
lexer::{self, Cursor, FullToken, Position},
|
lexer::{self, Cursor, FullToken, Position},
|
||||||
mir::{self, pass, Metadata, SourceModuleId},
|
mir::{self, pass, Metadata, SourceModuleId},
|
||||||
token_stream::{self, TokenRange},
|
token_stream::{self, TokenRange},
|
||||||
@ -30,6 +31,8 @@ pub enum ErrorKind {
|
|||||||
TypeInferenceError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>),
|
TypeInferenceError(#[source] mir::pass::Error<mir::typecheck::ErrorKind>),
|
||||||
#[error("{}{}", label("(Linker) "), .0.kind)]
|
#[error("{}{}", label("(Linker) "), .0.kind)]
|
||||||
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
|
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
|
||||||
|
#[error("{}{}", label("(Codegen) "), .0)]
|
||||||
|
CodegenError(#[from] codegen::ErrorKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorKind {
|
impl ErrorKind {
|
||||||
@ -50,6 +53,9 @@ impl ErrorKind {
|
|||||||
ErrorKind::TypeCheckError(error) => error.metadata,
|
ErrorKind::TypeCheckError(error) => error.metadata,
|
||||||
ErrorKind::TypeInferenceError(error) => error.metadata,
|
ErrorKind::TypeInferenceError(error) => error.metadata,
|
||||||
ErrorKind::LinkerError(error) => error.metadata,
|
ErrorKind::LinkerError(error) => error.metadata,
|
||||||
|
ErrorKind::CodegenError(error) => match error {
|
||||||
|
codegen::ErrorKind::Null => Default::default(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,7 +161,7 @@ impl ReidError {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_kind<U>(errors: Vec<ErrorKind>, map: ErrorModules) -> ReidError {
|
pub fn from_kind(errors: Vec<ErrorKind>, map: ErrorModules) -> ReidError {
|
||||||
ReidError { map, errors }
|
ReidError { map, errors }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
80
reid/src/ld.rs
Normal file
80
reid/src/ld.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
use std::{path::PathBuf, process::Command, thread, time::Duration};
|
||||||
|
|
||||||
|
pub struct LDRunner {
|
||||||
|
command: String,
|
||||||
|
dynamic_linker: String,
|
||||||
|
libraries: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LDRunner {
|
||||||
|
pub fn from_command(command: &str) -> LDRunner {
|
||||||
|
LDRunner {
|
||||||
|
command: command.to_owned(),
|
||||||
|
dynamic_linker: "ld-linux-x86-64.so.2".to_string(),
|
||||||
|
libraries: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_library(mut self, lib: &str) -> LDRunner {
|
||||||
|
self.libraries.push(lib.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invoke(&self, input: &PathBuf, out_path: &PathBuf) {
|
||||||
|
let input_path = input.canonicalize().unwrap();
|
||||||
|
|
||||||
|
let dyn_linker_path = find_objectfile(&self.dynamic_linker);
|
||||||
|
let crt1_path = find_objectfile("crt1.o");
|
||||||
|
|
||||||
|
println!("LDRunner: Using dynamic linker at: {:?}", dyn_linker_path);
|
||||||
|
|
||||||
|
let mut ld = Command::new(&self.command);
|
||||||
|
ld.arg("-dynamic-linker")
|
||||||
|
.arg(dyn_linker_path)
|
||||||
|
.arg(crt1_path);
|
||||||
|
|
||||||
|
for library in &self.libraries {
|
||||||
|
ld.arg(format!("-l{}", library));
|
||||||
|
}
|
||||||
|
|
||||||
|
ld.arg(input_path.to_str().unwrap())
|
||||||
|
.arg("-o")
|
||||||
|
.arg(out_path.to_str().unwrap());
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"LDRunner: Executing linker to objfile at {:?} => {:?}",
|
||||||
|
input_path, out_path
|
||||||
|
);
|
||||||
|
dbg!(&ld);
|
||||||
|
|
||||||
|
ld.spawn().expect("Unable to execute ld!");
|
||||||
|
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
|
||||||
|
println!("Setting executable bit to {:?}..", out_path);
|
||||||
|
Command::new("chmod")
|
||||||
|
.arg("+x")
|
||||||
|
.arg(out_path)
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_objectfile(name: &str) -> String {
|
||||||
|
let whereis = Command::new("whereis")
|
||||||
|
.arg(&name)
|
||||||
|
.output()
|
||||||
|
.expect("Unable to execute whereis");
|
||||||
|
let whereis_output = String::from_utf8(whereis.stdout).unwrap();
|
||||||
|
|
||||||
|
whereis_output
|
||||||
|
.split(" ")
|
||||||
|
.skip(1)
|
||||||
|
.next()
|
||||||
|
.expect(&format!("Unable to find {}: {}", name, whereis_output))
|
||||||
|
.split("\n")
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.to_owned()
|
||||||
|
}
|
@ -2,7 +2,7 @@ use std::{fmt::Debug, str::Chars};
|
|||||||
|
|
||||||
static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
static DECIMAL_NUMERICS: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, PartialOrd, Ord)]
|
#[derive(Eq, PartialEq, Clone, PartialOrd, Ord)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
/// Values
|
/// Values
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
@ -56,6 +56,10 @@ pub enum Token {
|
|||||||
Star,
|
Star,
|
||||||
/// `-`
|
/// `-`
|
||||||
Minus,
|
Minus,
|
||||||
|
/// `/`
|
||||||
|
Slash,
|
||||||
|
/// `%`
|
||||||
|
Percent,
|
||||||
|
|
||||||
/// `>`
|
/// `>`
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
@ -83,6 +87,8 @@ pub enum Token {
|
|||||||
/// `.`
|
/// `.`
|
||||||
Dot,
|
Dot,
|
||||||
|
|
||||||
|
Unknown(char),
|
||||||
|
|
||||||
Eof,
|
Eof,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +155,18 @@ impl ToString for Token {
|
|||||||
Token::Comma => String::from(','),
|
Token::Comma => String::from(','),
|
||||||
Token::Dot => String::from('.'),
|
Token::Dot => String::from('.'),
|
||||||
Token::Eof => String::new(),
|
Token::Eof => String::new(),
|
||||||
|
Token::Slash => String::from('/'),
|
||||||
|
Token::Percent => String::from('%'),
|
||||||
|
Token::Unknown(val) => val.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Token {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Unknown(value) => write!(f, "Unknown(\'{}\')", value.to_string()),
|
||||||
|
_ => write!(f, "{}", self.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +181,7 @@ pub struct FullToken {
|
|||||||
impl Debug for FullToken {
|
impl Debug for FullToken {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_fmt(format_args!(
|
f.write_fmt(format_args!(
|
||||||
"{:?} (Ln {}, Col {})",
|
"Token({:?}) (Ln {}, Col {})",
|
||||||
self.token, self.position.1, self.position.0
|
self.token, self.position.1, self.position.0
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -343,8 +361,10 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
|||||||
'}' => Token::BraceClose,
|
'}' => Token::BraceClose,
|
||||||
',' => Token::Comma,
|
',' => Token::Comma,
|
||||||
'.' => Token::Dot,
|
'.' => Token::Dot,
|
||||||
// Invalid token
|
'/' => Token::Slash,
|
||||||
_ => Err(Error::InvalidToken(*character, cursor.position))?,
|
'%' => Token::Percent,
|
||||||
|
// Unknown token
|
||||||
|
value => Token::Unknown(*value),
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.push(FullToken {
|
tokens.push(FullToken {
|
||||||
|
@ -54,7 +54,8 @@ use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream};
|
|||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
mod error_raporting;
|
pub mod error_raporting;
|
||||||
|
pub mod ld;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
pub mod mir;
|
pub mod mir;
|
||||||
mod pad_adapter;
|
mod pad_adapter;
|
||||||
@ -137,7 +138,7 @@ pub fn perform_all_passes<'map>(
|
|||||||
dbg!(&state);
|
dbg!(&state);
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::from_kind::<()>(
|
return Err(ReidError::from_kind(
|
||||||
state.errors.iter().map(|e| e.clone().into()).collect(),
|
state.errors.iter().map(|e| e.clone().into()).collect(),
|
||||||
module_map.clone(),
|
module_map.clone(),
|
||||||
));
|
));
|
||||||
@ -157,7 +158,7 @@ pub fn perform_all_passes<'map>(
|
|||||||
dbg!(&state);
|
dbg!(&state);
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::from_kind::<()>(
|
return Err(ReidError::from_kind(
|
||||||
state
|
state
|
||||||
.errors
|
.errors
|
||||||
.iter()
|
.iter()
|
||||||
@ -177,7 +178,7 @@ pub fn perform_all_passes<'map>(
|
|||||||
dbg!(&state);
|
dbg!(&state);
|
||||||
|
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::from_kind::<()>(
|
return Err(ReidError::from_kind(
|
||||||
state
|
state
|
||||||
.errors
|
.errors
|
||||||
.iter()
|
.iter()
|
||||||
@ -214,7 +215,10 @@ pub fn compile_and_pass<'map>(
|
|||||||
println!("{}", &mir_context);
|
println!("{}", &mir_context);
|
||||||
|
|
||||||
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
|
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
|
||||||
let codegen_modules = mir_context.codegen(&mut context);
|
let codegen_modules = match mir_context.codegen(&mut context) {
|
||||||
|
Ok(modules) => modules,
|
||||||
|
Err(e) => Err(ReidError::from_kind(vec![e.into()], module_map.clone()))?,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("{}", &codegen_modules.context);
|
println!("{}", &codegen_modules.context);
|
||||||
|
@ -32,7 +32,7 @@ impl Display for Context {
|
|||||||
|
|
||||||
impl Display for Module {
|
impl Display for Module {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
writeln!(f, "Module({}) {{", self.name)?;
|
writeln!(f, "Module({}) ({}) {{", self.name, self.module_id)?;
|
||||||
|
|
||||||
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);
|
||||||
@ -299,6 +299,8 @@ impl Display for BinaryOperator {
|
|||||||
BinaryOperator::Mult => write!(f, "*"),
|
BinaryOperator::Mult => write!(f, "*"),
|
||||||
BinaryOperator::And => write!(f, "&&"),
|
BinaryOperator::And => write!(f, "&&"),
|
||||||
BinaryOperator::Cmp(op) => Display::fmt(op, f),
|
BinaryOperator::Cmp(op) => Display::fmt(op, f),
|
||||||
|
BinaryOperator::Div => write!(f, "/"),
|
||||||
|
BinaryOperator::Mod => write!(f, "%"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,7 +326,7 @@ impl Display for Metadata {
|
|||||||
|
|
||||||
impl Display for SourceModuleId {
|
impl Display for SourceModuleId {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "Mod {}", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,7 +364,7 @@ impl Display for TypeKind {
|
|||||||
Display::fmt(len, f)?;
|
Display::fmt(len, f)?;
|
||||||
f.write_char(']')
|
f.write_char(']')
|
||||||
}
|
}
|
||||||
TypeKind::CustomType(CustomTypeKey(name, mod_id)) => write!(f, "{}:{}", mod_id, name),
|
TypeKind::CustomType(CustomTypeKey(name, mod_id)) => write!(f, "{}@{}", name, mod_id),
|
||||||
TypeKind::Borrow(type_kind, false) => {
|
TypeKind::Borrow(type_kind, false) => {
|
||||||
write!(f, "&")?;
|
write!(f, "&")?;
|
||||||
Display::fmt(type_kind, f)
|
Display::fmt(type_kind, f)
|
||||||
|
@ -104,14 +104,20 @@ impl TypeKind {
|
|||||||
BinaryOperator::Mult => self.clone(),
|
BinaryOperator::Mult => self.clone(),
|
||||||
BinaryOperator::And => TypeKind::Bool,
|
BinaryOperator::And => TypeKind::Bool,
|
||||||
BinaryOperator::Cmp(_) => TypeKind::Bool,
|
BinaryOperator::Cmp(_) => TypeKind::Bool,
|
||||||
|
BinaryOperator::Div => self.clone(),
|
||||||
|
BinaryOperator::Mod => self.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reverse of binop_type, where the given hint is the known required output
|
||||||
|
/// type of the binop, and the output is the hint for the lhs/rhs type.
|
||||||
pub fn binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> {
|
pub fn binop_hint(&self, op: &BinaryOperator) -> Option<TypeKind> {
|
||||||
match op {
|
match op {
|
||||||
BinaryOperator::Add | BinaryOperator::Minus | BinaryOperator::Mult => {
|
BinaryOperator::Add
|
||||||
Some(self.clone())
|
| BinaryOperator::Minus
|
||||||
}
|
| BinaryOperator::Mult
|
||||||
|
| BinaryOperator::Div
|
||||||
|
| BinaryOperator::Mod => Some(self.clone()),
|
||||||
BinaryOperator::And => None,
|
BinaryOperator::And => None,
|
||||||
BinaryOperator::Cmp(_) => None,
|
BinaryOperator::Cmp(_) => None,
|
||||||
}
|
}
|
||||||
@ -465,12 +471,16 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_zero(&self) -> Option<bool> {
|
pub fn is_zero(&self) -> Result<Option<bool>, ErrorKind> {
|
||||||
Some(self.num_value()? == 0)
|
if let Some(val) = self.num_value()? {
|
||||||
|
Ok(Some(val == 0))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_value(&self) -> Option<i128> {
|
pub fn num_value(&self) -> Result<Option<i128>, ErrorKind> {
|
||||||
match &self.0 {
|
Ok(match &self.0 {
|
||||||
ExprKind::Variable(_) => None,
|
ExprKind::Variable(_) => None,
|
||||||
ExprKind::Indexed(..) => None,
|
ExprKind::Indexed(..) => None,
|
||||||
ExprKind::Accessed(..) => None,
|
ExprKind::Accessed(..) => None,
|
||||||
@ -478,22 +488,46 @@ impl Expression {
|
|||||||
ExprKind::Struct(..) => None,
|
ExprKind::Struct(..) => None,
|
||||||
ExprKind::Literal(literal) => literal.num_value(),
|
ExprKind::Literal(literal) => literal.num_value(),
|
||||||
ExprKind::BinOp(op, lhs, rhs) => match op {
|
ExprKind::BinOp(op, lhs, rhs) => match op {
|
||||||
BinaryOperator::Add => Some(lhs.num_value()? + rhs.num_value()?),
|
BinaryOperator::Add => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a + b),
|
||||||
BinaryOperator::Minus => Some(lhs.num_value()? - rhs.num_value()?),
|
BinaryOperator::Minus => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a - b),
|
||||||
BinaryOperator::Mult => Some(lhs.num_value()? * rhs.num_value()?),
|
BinaryOperator::Mult => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a * b),
|
||||||
BinaryOperator::And => None,
|
BinaryOperator::And => None,
|
||||||
BinaryOperator::Cmp(_) => None,
|
BinaryOperator::Cmp(_) => None,
|
||||||
|
BinaryOperator::Div => {
|
||||||
|
let rhs_value = rhs.num_value()?;
|
||||||
|
if rhs_value == Some(0) {
|
||||||
|
Err(ErrorKind::DivideZero)?
|
||||||
|
}
|
||||||
|
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b)
|
||||||
|
}
|
||||||
|
BinaryOperator::Mod => {
|
||||||
|
let rhs_value = rhs.num_value()?;
|
||||||
|
if rhs_value == Some(0) {
|
||||||
|
Err(ErrorKind::DivideZero)?
|
||||||
|
}
|
||||||
|
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a % b)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ExprKind::FunctionCall(..) => None,
|
ExprKind::FunctionCall(..) => None,
|
||||||
ExprKind::If(_) => None,
|
ExprKind::If(_) => None,
|
||||||
ExprKind::Block(_) => None,
|
ExprKind::Block(_) => None,
|
||||||
ExprKind::Borrow(_, _) => None,
|
ExprKind::Borrow(_, _) => None,
|
||||||
ExprKind::Deref(_) => None,
|
ExprKind::Deref(_) => None,
|
||||||
ExprKind::CastTo(expression, _) => expression.num_value(),
|
ExprKind::CastTo(expression, _) => expression.num_value()?,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maybe<T>(lhs: Option<i128>, rhs: Option<i128>, fun: T) -> Option<i128>
|
||||||
|
where
|
||||||
|
T: FnOnce(i128, i128) -> i128,
|
||||||
|
{
|
||||||
|
if let (Some(lhs), Some(rhs)) = (lhs, rhs) {
|
||||||
|
Some(fun(lhs, rhs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
impl IfExpression {
|
impl IfExpression {
|
||||||
pub fn return_type(
|
pub fn return_type(
|
||||||
&self,
|
&self,
|
||||||
|
@ -103,6 +103,8 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
|
|
||||||
let mut modules_to_process: Vec<Rc<RefCell<_>>> = modules.values().cloned().collect();
|
let mut modules_to_process: Vec<Rc<RefCell<_>>> = modules.values().cloned().collect();
|
||||||
|
|
||||||
|
let mut already_imported_types = HashSet::<CustomTypeKey>::new();
|
||||||
|
|
||||||
while let Some(module) = modules_to_process.pop() {
|
while let Some(module) = modules_to_process.pop() {
|
||||||
let mut importer_module = module.borrow_mut();
|
let mut importer_module = module.borrow_mut();
|
||||||
|
|
||||||
@ -232,28 +234,30 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_type(_: &String, ty: &TypeKind) -> (TypeKind, Vec<CustomTypeKey>) {
|
fn import_type(ty: &TypeKind) -> Vec<CustomTypeKey> {
|
||||||
let mut imported_types = Vec::new();
|
let mut imported_types = Vec::new();
|
||||||
let ty = match &ty {
|
match &ty {
|
||||||
TypeKind::CustomType(key) => {
|
TypeKind::CustomType(key) => imported_types.push(key.clone()),
|
||||||
imported_types.push(key.clone());
|
TypeKind::Borrow(ty, _) => imported_types.extend(import_type(ty)),
|
||||||
TypeKind::CustomType(key.clone())
|
TypeKind::Array(ty, _) => imported_types.extend(import_type(ty)),
|
||||||
}
|
TypeKind::UserPtr(ty) => imported_types.extend(import_type(ty)),
|
||||||
_ => ty.clone(),
|
TypeKind::CodegenPtr(ty) => imported_types.extend(import_type(ty)),
|
||||||
|
_ => {}
|
||||||
};
|
};
|
||||||
(ty, imported_types)
|
imported_types
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut imported_types = Vec::new();
|
let mut imported_types = Vec::new();
|
||||||
|
|
||||||
let (return_type, types) = import_type(&imported_mod_name, &func.return_type);
|
let types = import_type(&func.return_type);
|
||||||
|
let return_type = func.return_type.clone();
|
||||||
imported_types.extend(types);
|
imported_types.extend(types);
|
||||||
|
|
||||||
let mut param_tys = Vec::new();
|
let mut param_tys = Vec::new();
|
||||||
for (param_name, param_ty) in &func.parameters {
|
for (param_name, param_ty) in &func.parameters {
|
||||||
let (param_type, types) = import_type(&imported_mod_name, ¶m_ty);
|
let types = import_type(¶m_ty);
|
||||||
imported_types.extend(types);
|
imported_types.extend(types);
|
||||||
param_tys.push((param_name.clone(), param_type));
|
param_tys.push((param_name.clone(), param_ty.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_inner_types(
|
fn find_inner_types(
|
||||||
@ -303,6 +307,14 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
seen.extend(inner);
|
seen.extend(inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Unable to import same-named type from multiple places..
|
||||||
|
let seen = seen
|
||||||
|
.difference(&already_imported_types)
|
||||||
|
.cloned()
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
|
already_imported_types.extend(seen.clone());
|
||||||
|
|
||||||
for typekey in seen.into_iter() {
|
for typekey in seen.into_iter() {
|
||||||
let typedef = imported_mod_typedefs
|
let typedef = imported_mod_typedefs
|
||||||
.iter()
|
.iter()
|
||||||
@ -317,9 +329,10 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
name: func_name,
|
name: func_name,
|
||||||
is_pub: false,
|
is_pub: false,
|
||||||
is_imported: false,
|
is_imported: false,
|
||||||
return_type: return_type,
|
return_type,
|
||||||
parameters: param_tys,
|
parameters: param_tys,
|
||||||
kind: super::FunctionDefinitionKind::Extern(true),
|
kind: super::FunctionDefinitionKind::Extern(true),
|
||||||
|
source: imported_mod_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +218,8 @@ pub enum BinaryOperator {
|
|||||||
Add,
|
Add,
|
||||||
Minus,
|
Minus,
|
||||||
Mult,
|
Mult,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
And,
|
And,
|
||||||
Cmp(CmpOperator),
|
Cmp(CmpOperator),
|
||||||
}
|
}
|
||||||
@ -291,6 +293,7 @@ pub struct FunctionDefinition {
|
|||||||
pub return_type: TypeKind,
|
pub return_type: TypeKind,
|
||||||
pub parameters: Vec<(String, TypeKind)>,
|
pub parameters: Vec<(String, TypeKind)>,
|
||||||
pub kind: FunctionDefinitionKind,
|
pub kind: FunctionDefinitionKind,
|
||||||
|
pub source: SourceModuleId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -295,7 +295,7 @@ impl Module {
|
|||||||
scope
|
scope
|
||||||
.types
|
.types
|
||||||
.set(
|
.set(
|
||||||
CustomTypeKey(typedef.name.clone(), self.module_id),
|
CustomTypeKey(typedef.name.clone(), typedef.source_module),
|
||||||
typedef.clone(),
|
typedef.clone(),
|
||||||
)
|
)
|
||||||
.ok();
|
.ok();
|
||||||
|
@ -68,6 +68,8 @@ pub enum ErrorKind {
|
|||||||
NegativeUnsignedValue(TypeKind),
|
NegativeUnsignedValue(TypeKind),
|
||||||
#[error("Cannot cast type {0} into type {1}!")]
|
#[error("Cannot cast type {0} into type {1}!")]
|
||||||
NotCastableTo(TypeKind, TypeKind),
|
NotCastableTo(TypeKind, TypeKind),
|
||||||
|
#[error("Cannot divide by zero")]
|
||||||
|
DivideZero,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Struct used to implement a type-checking pass that can be performed on the
|
/// Struct used to implement a type-checking pass that can be performed on the
|
||||||
@ -426,7 +428,7 @@ impl Expression {
|
|||||||
let both_t = lhs_type.collapse_into(&rhs_type)?;
|
let both_t = lhs_type.collapse_into(&rhs_type)?;
|
||||||
|
|
||||||
if *op == BinaryOperator::Minus && !lhs_type.signed() {
|
if *op == BinaryOperator::Minus && !lhs_type.signed() {
|
||||||
if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value(), rhs.num_value()) {
|
if let (Some(lhs_val), Some(rhs_val)) = (lhs.num_value()?, rhs.num_value()?) {
|
||||||
if lhs_val < rhs_val {
|
if lhs_val < rhs_val {
|
||||||
return Err(ErrorKind::NegativeUnsignedValue(lhs_type));
|
return Err(ErrorKind::NegativeUnsignedValue(lhs_type));
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ impl std::iter::Sum for TokenRange {
|
|||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Expected {} got \"{}\"", .0, .1.to_string())]
|
#[error("Expected {} got \"{:?}\"", .0, .1)]
|
||||||
Expected(String, Token, TokenRange),
|
Expected(String, Token, TokenRange),
|
||||||
#[error("Source file contains no tokens")]
|
#[error("Source file contains no tokens")]
|
||||||
FileEmpty,
|
FileEmpty,
|
||||||
|
@ -1,79 +1,122 @@
|
|||||||
|
use std::{
|
||||||
|
alloc::System,
|
||||||
|
path::PathBuf,
|
||||||
|
process::Command,
|
||||||
|
thread,
|
||||||
|
time::{Duration, SystemTime},
|
||||||
|
};
|
||||||
|
|
||||||
use reid::{
|
use reid::{
|
||||||
compile_module,
|
compile_module,
|
||||||
|
ld::LDRunner,
|
||||||
mir::{self},
|
mir::{self},
|
||||||
parse_module, perform_all_passes,
|
parse_module, perform_all_passes,
|
||||||
};
|
};
|
||||||
|
use reid_lib::Context;
|
||||||
use util::assert_err;
|
use util::assert_err;
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
fn test(source: &str, name: &str) {
|
fn test(source: &str, name: &str, expected_exit_code: i32) {
|
||||||
let mut map = Default::default();
|
assert_err(assert_err(std::panic::catch_unwind(|| {
|
||||||
let (id, tokens) = assert_err(parse_module(source, name, &mut map));
|
let mut map = Default::default();
|
||||||
let module = assert_err(compile_module(id, tokens, &mut map, None, true));
|
let (id, tokens) = assert_err(parse_module(source, name, &mut map));
|
||||||
|
|
||||||
assert_err(perform_all_passes(
|
let module = assert_err(compile_module(id, tokens, &mut map, None, true));
|
||||||
&mut mir::Context::from(vec![module], Default::default()),
|
let mut mir_context = mir::Context::from(vec![module], Default::default());
|
||||||
&mut map,
|
assert_err(perform_all_passes(&mut mir_context, &mut map));
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static ARRAY: &str = include_str!("../../reid_src/array.reid");
|
let context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
|
||||||
pub static FIBONACCI: &str = include_str!("../../reid_src/fibonacci.reid");
|
|
||||||
pub static HELLO_WORLD: &str = include_str!("../../reid_src/hello_world.reid");
|
|
||||||
pub static MUTABLE: &str = include_str!("../../reid_src/mutable.reid");
|
|
||||||
pub static STRINGS: &str = include_str!("../../reid_src/strings.reid");
|
|
||||||
pub static STRUCTS: &str = include_str!("../../reid_src/struct.reid");
|
|
||||||
pub static ARRAY_STRUCTS: &str = include_str!("../../reid_src/array_structs.reid");
|
|
||||||
pub static BORROW: &str = include_str!("../../reid_src/borrow.reid");
|
|
||||||
pub static ARITHMETIC: &str = include_str!("../../reid_src/arithmetic.reid");
|
|
||||||
|
|
||||||
#[test]
|
let codegen = assert_err(mir_context.codegen(&context));
|
||||||
fn array_compiles_well() {
|
|
||||||
test(ARRAY, "array");
|
let output = codegen.compile().output();
|
||||||
|
let time = SystemTime::now();
|
||||||
|
let in_path = PathBuf::from(format!(
|
||||||
|
"/tmp/temp-{}.o",
|
||||||
|
time.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos()
|
||||||
|
));
|
||||||
|
|
||||||
|
std::fs::write(&in_path, &output.obj_buffer).expect("Could not write OBJ-file!");
|
||||||
|
|
||||||
|
let out_path = in_path.with_extension("out");
|
||||||
|
LDRunner::from_command("ld")
|
||||||
|
.with_library("c")
|
||||||
|
.invoke(&in_path, &out_path);
|
||||||
|
std::fs::remove_file(in_path).unwrap();
|
||||||
|
|
||||||
|
let executed = Command::new(&out_path).output();
|
||||||
|
std::fs::remove_file(out_path).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(expected_exit_code, executed.unwrap().status.code().unwrap());
|
||||||
|
|
||||||
|
Ok::<(), ()>(())
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fibonacci_compiles_well() {
|
fn arithmetic_compiles_well() {
|
||||||
test(FIBONACCI, "fibonacci");
|
test(include_str!("../../examples/arithmetic.reid"), "test", 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn hello_world_compiles_well() {
|
|
||||||
test(HELLO_WORLD, "hello_world");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn mutable_compiles_well() {
|
|
||||||
test(MUTABLE, "mutable");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn strings_compiles_well() {
|
|
||||||
test(STRINGS, "strings");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn arrays_compiles_well() {
|
|
||||||
test(ARRAY, "array");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn struct_compiles_well() {
|
|
||||||
test(STRUCTS, "struct");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn array_structs_compiles_well() {
|
fn array_structs_compiles_well() {
|
||||||
test(ARRAY_STRUCTS, "array_structs");
|
test(include_str!("../../examples/array_structs.reid"), "test", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn borrow_structs_compiles_well() {
|
fn array_compiles_well() {
|
||||||
test(BORROW, "borrow");
|
test(include_str!("../../examples/array.reid"), "test", 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn arithmetic_structs_compiles_well() {
|
fn borrow_compiles_well() {
|
||||||
test(ARITHMETIC, "arithmetic");
|
test(include_str!("../../examples/borrow.reid"), "test", 17);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn borrow_hard_compiles_well() {
|
||||||
|
test(include_str!("../../examples/borrow_hard.reid"), "test", 17);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn cast_compiles_well() {
|
||||||
|
test(include_str!("../../examples/cast.reid"), "test", 6);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn char_compiles_well() {
|
||||||
|
test(include_str!("../../examples/char.reid"), "test", 98);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn div_mod_compiles_well() {
|
||||||
|
test(include_str!("../../examples/div_mod.reid"), "test", 12);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn fibonacci_compiles_well() {
|
||||||
|
test(include_str!("../../examples/fibonacci.reid"), "test", 1);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn float_compiles_well() {
|
||||||
|
test(include_str!("../../examples/float.reid"), "test", 1);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn hello_world_compiles_well() {
|
||||||
|
test(include_str!("../../examples/hello_world.reid"), "test", 0);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn mutable_compiles_well() {
|
||||||
|
test(include_str!("../../examples/mutable.reid"), "test", 21);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn ptr_compiles_well() {
|
||||||
|
test(include_str!("../../examples/ptr.reid"), "test", 5);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn std_test_compiles_well() {
|
||||||
|
test(include_str!("../../examples/std_test.reid"), "test", 3);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn strings_compiles_well() {
|
||||||
|
test(include_str!("../../examples/strings.reid"), "test", 5);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn struct_compiles_well() {
|
||||||
|
test(include_str!("../../examples/struct.reid"), "test", 17);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user