Compare commits
No commits in common. "0a90ac449781477f922ac37440fc6a56b0fc83b0" and "682295b04a5087b37da9cf3f3c4fdd1b7c992166" have entirely different histories.
0a90ac4497
...
682295b04a
2
Makefile
2
Makefile
@ -3,7 +3,7 @@ BIN=$(SRC:.reid=.out)
|
|||||||
|
|
||||||
REID=cargo run --example cli
|
REID=cargo run --example cli
|
||||||
LD=ld
|
LD=ld
|
||||||
LDFLAGS=-lSDL3
|
LDFLAGS=
|
||||||
|
|
||||||
all: $(BIN)
|
all: $(BIN)
|
||||||
clean:
|
clean:
|
||||||
|
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;
|
|
||||||
}
|
|
@ -199,7 +199,6 @@ pub struct BlockData {
|
|||||||
deleted: bool,
|
deleted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Block<'builder> {
|
pub struct Block<'builder> {
|
||||||
phantom: PhantomData<&'builder ()>,
|
phantom: PhantomData<&'builder ()>,
|
||||||
builder: Builder,
|
builder: Builder,
|
||||||
|
@ -14,6 +14,6 @@ color = ["colored"]
|
|||||||
[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 = "0.1.0" }
|
reid-lib = { path = "../reid-llvm-lib" }
|
||||||
|
|
||||||
colored = {version = "3.0.0", optional = true}
|
colored = {version = "3.0.0", optional = true}
|
@ -94,13 +94,13 @@ 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 == 0 { add_char(string, '0'); }
|
||||||
else if num == 1 { add_char(string, '1'); }
|
else { if num == 1 { add_char(string, '1'); }
|
||||||
else if num == 2 { add_char(string, '2'); }
|
else { if num == 2 { add_char(string, '2'); }
|
||||||
else if num == 3 { add_char(string, '3'); }
|
else { if num == 3 { add_char(string, '3'); }
|
||||||
else if num == 4 { add_char(string, '4'); }
|
else { if num == 4 { add_char(string, '4'); }
|
||||||
else if num == 5 { add_char(string, '5'); }
|
else { if num == 5 { add_char(string, '5'); }
|
||||||
else if num == 6 { add_char(string, '6'); }
|
else { if num == 6 { add_char(string, '6'); }
|
||||||
else if num == 7 { add_char(string, '7'); }
|
else { if num == 7 { add_char(string, '7'); }
|
||||||
else if num == 8 { add_char(string, '8'); }
|
else { if num == 8 { add_char(string, '8'); }
|
||||||
else if num == 9 { add_char(string, '9'); }
|
else { if num == 9 { add_char(string, '9'); } } } } } } } } } }
|
||||||
}
|
}
|
@ -115,8 +115,8 @@ pub struct FunctionCallExpression(pub String, pub Vec<Expression>, pub TokenRang
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IfExpression(
|
pub struct IfExpression(
|
||||||
pub Expression,
|
pub Expression,
|
||||||
pub Expression,
|
pub Block,
|
||||||
pub Option<Expression>,
|
pub Option<Block>,
|
||||||
#[allow(dead_code)] pub TokenRange,
|
#[allow(dead_code)] pub TokenRange,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ use std::path::PathBuf;
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::{self},
|
ast::{self},
|
||||||
mir::{
|
mir::{
|
||||||
self, CustomTypeKey, ModuleMap, NamedVariableRef, SourceModuleId, StmtKind, StructField,
|
self, ModuleMap, NamedVariableRef, SourceModuleId, StmtKind, StructField, StructType,
|
||||||
StructType,
|
CustomTypeKey,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -205,17 +205,13 @@ impl ast::Expression {
|
|||||||
}
|
}
|
||||||
ast::ExpressionKind::IfExpr(if_expression) => {
|
ast::ExpressionKind::IfExpr(if_expression) => {
|
||||||
let cond = if_expression.0.process(module_id);
|
let cond = if_expression.0.process(module_id);
|
||||||
let then_block = if_expression.1.process(module_id);
|
let then_block = if_expression.1.into_mir(module_id);
|
||||||
let else_block = if let Some(el) = &if_expression.2 {
|
let else_block = if let Some(el) = &if_expression.2 {
|
||||||
Some(el.process(module_id))
|
Some(el.into_mir(module_id))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
mir::ExprKind::If(mir::IfExpression(
|
mir::ExprKind::If(mir::IfExpression(Box::new(cond), then_block, else_block))
|
||||||
Box::new(cond),
|
|
||||||
Box::new(then_block),
|
|
||||||
Box::new(else_block),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
ast::ExpressionKind::Array(expressions) => {
|
ast::ExpressionKind::Array(expressions) => {
|
||||||
mir::ExprKind::Array(expressions.iter().map(|e| e.process(module_id)).collect())
|
mir::ExprKind::Array(expressions.iter().map(|e| e.process(module_id)).collect())
|
||||||
|
@ -746,19 +746,16 @@ impl mir::Expression {
|
|||||||
}
|
}
|
||||||
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 mut inner_scope = scope.with_block(scope.function.ir.block("inner"));
|
||||||
scope.block.terminate(Term::Br(inner.value())).unwrap();
|
if let Some(ret) = block.codegen(&mut inner_scope, state) {
|
||||||
|
inner_scope
|
||||||
let mut inner_scope = scope.with_block(inner);
|
.block
|
||||||
let ret = if let Some(ret) = block.codegen(&mut inner_scope, state) {
|
.terminate(Term::Br(scope.block.value()))
|
||||||
|
.unwrap();
|
||||||
Some(ret)
|
Some(ret)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
}
|
||||||
let outer = scope.function.ir.block("outer");
|
|
||||||
inner_scope.block.terminate(Term::Br(outer.value())).ok();
|
|
||||||
scope.swap_block(outer);
|
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
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
|
||||||
@ -1141,12 +1138,19 @@ impl mir::IfExpression {
|
|||||||
let before_v = debug.info.location(&debug.scope, before_location);
|
let before_v = debug.info.location(&debug.scope, before_location);
|
||||||
scope.block.set_terminator_location(before_v).ok();
|
scope.block.set_terminator_location(before_v).ok();
|
||||||
|
|
||||||
let then_location = self.1 .1.into_debug(scope.tokens, debug.scope).unwrap();
|
let then_location = self
|
||||||
|
.1
|
||||||
|
.return_meta()
|
||||||
|
.into_debug(scope.tokens, debug.scope)
|
||||||
|
.unwrap();
|
||||||
let then_v = debug.info.location(&debug.scope, then_location);
|
let then_v = debug.info.location(&debug.scope, then_location);
|
||||||
then_b.set_terminator_location(then_v).unwrap();
|
then_b.set_terminator_location(then_v).unwrap();
|
||||||
|
|
||||||
let else_location = if let Some(else_expr) = self.2.as_ref() {
|
let else_location = if let Some(else_block) = &self.2 {
|
||||||
else_expr.1.into_debug(scope.tokens, debug.scope).unwrap()
|
else_block
|
||||||
|
.return_meta()
|
||||||
|
.into_debug(scope.tokens, debug.scope)
|
||||||
|
.unwrap()
|
||||||
} else {
|
} else {
|
||||||
then_location
|
then_location
|
||||||
};
|
};
|
||||||
@ -1164,7 +1168,7 @@ impl mir::IfExpression {
|
|||||||
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_block) = &self.2 {
|
||||||
let mut else_scope = scope.with_block(else_b);
|
let mut else_scope = scope.with_block(else_b);
|
||||||
|
|
||||||
scope
|
scope
|
||||||
@ -1172,7 +1176,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_block.codegen(&mut else_scope, state);
|
||||||
|
|
||||||
else_scope.block.terminate(Term::Br(after_bb)).ok();
|
else_scope.block.terminate(Term::Br(after_bb)).ok();
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
|||||||
match character {
|
match character {
|
||||||
'\'' => Token::CharLit(value),
|
'\'' => Token::CharLit(value),
|
||||||
'\"' => Token::StringLit(value),
|
'\"' => Token::StringLit(value),
|
||||||
_ => unreachable!(),
|
_ => unsafe { unreachable_unchecked() },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// "words"
|
// "words"
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
use std::{env, fs, path::PathBuf};
|
|
||||||
|
|
||||||
use reid::compile_simple;
|
|
||||||
use reid_lib::compile::CompileOutput;
|
|
||||||
|
|
||||||
fn main() -> Result<(), std::io::Error> {
|
|
||||||
let args: Vec<String> = env::args().collect();
|
|
||||||
if let Some(filename) = args.get(1) {
|
|
||||||
let path = PathBuf::from(filename).canonicalize().unwrap();
|
|
||||||
let parent = path.with_extension("");
|
|
||||||
let llvm_ir_path = parent.with_extension("ll");
|
|
||||||
let object_path = parent.with_extension("o");
|
|
||||||
let asm_path = parent.with_extension("asm");
|
|
||||||
|
|
||||||
let before = std::time::SystemTime::now();
|
|
||||||
|
|
||||||
let text = fs::read_to_string(&path)?;
|
|
||||||
match compile_simple(&text, PathBuf::from(&path)) {
|
|
||||||
Ok(CompileOutput {
|
|
||||||
triple,
|
|
||||||
assembly,
|
|
||||||
obj_buffer,
|
|
||||||
llvm_ir,
|
|
||||||
}) => {
|
|
||||||
println!("{}", llvm_ir);
|
|
||||||
|
|
||||||
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);
|
|
||||||
println!(
|
|
||||||
"Compilation took: {:.2}ms\n",
|
|
||||||
(after.duration_since(before).unwrap().as_micros() as f32) / 1000.
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(e) => panic!("{}", e),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
println!("Please input compiled file path!")
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -240,7 +240,7 @@ impl Display for IfExpression {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "if {} ", self.0)?;
|
write!(f, "if {} ", self.0)?;
|
||||||
Display::fmt(&self.1, f)?;
|
Display::fmt(&self.1, f)?;
|
||||||
if let Some(e) = self.2.as_ref() {
|
if let Some(e) = &self.2 {
|
||||||
Display::fmt(&e, f)?;
|
Display::fmt(&e, f)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -491,8 +491,8 @@ impl IfExpression {
|
|||||||
mod_id: SourceModuleId,
|
mod_id: SourceModuleId,
|
||||||
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||||
let then_r = self.1.return_type(refs, mod_id)?;
|
let then_r = self.1.return_type(refs, mod_id)?;
|
||||||
if let Some(else_e) = self.2.as_ref() {
|
if let Some(else_b) = &self.2 {
|
||||||
let else_r = else_e.return_type(refs, mod_id)?;
|
let else_r = else_b.return_type(refs, mod_id)?;
|
||||||
|
|
||||||
let kind = if then_r.0 == ReturnKind::Hard && else_r.0 == ReturnKind::Hard {
|
let kind = if then_r.0 == ReturnKind::Hard && else_r.0 == ReturnKind::Hard {
|
||||||
ReturnKind::Hard
|
ReturnKind::Hard
|
||||||
|
@ -267,11 +267,7 @@ pub struct Expression(pub ExprKind, pub Metadata);
|
|||||||
|
|
||||||
/// Condition, Then, Else
|
/// Condition, Then, Else
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IfExpression(
|
pub struct IfExpression(pub Box<Expression>, pub Block, pub Option<Block>);
|
||||||
pub Box<Expression>,
|
|
||||||
pub Box<Expression>,
|
|
||||||
pub Box<Option<Expression>>,
|
|
||||||
);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionCall {
|
pub struct FunctionCall {
|
||||||
|
@ -491,31 +491,46 @@ impl Expression {
|
|||||||
// Typecheck then/else return types and make sure they are the
|
// Typecheck then/else return types and make sure they are the
|
||||||
// same, if else exists.
|
// same, if else exists.
|
||||||
let then_res = lhs.typecheck(state, &typerefs, hint_t);
|
let then_res = lhs.typecheck(state, &typerefs, hint_t);
|
||||||
let then_ret_t = state.or_else(then_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
let (then_ret_kind, then_ret_t) = state.or_else(
|
||||||
let else_ret_t = if let Some(else_expr) = rhs.as_mut() {
|
then_res,
|
||||||
let res = else_expr.typecheck(state, &typerefs, hint_t);
|
(ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)),
|
||||||
let else_ret_t =
|
lhs.meta,
|
||||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), else_expr.1);
|
);
|
||||||
|
let else_ret_t = if let Some(else_block) = rhs {
|
||||||
|
let res = else_block.typecheck(state, &typerefs, hint_t);
|
||||||
|
let (else_ret_kind, else_ret_t) = state.or_else(
|
||||||
|
res,
|
||||||
|
(ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)),
|
||||||
|
else_block.meta,
|
||||||
|
);
|
||||||
|
|
||||||
else_ret_t
|
if else_ret_kind == ReturnKind::Hard {
|
||||||
|
TypeKind::Void
|
||||||
|
} else {
|
||||||
|
else_ret_t
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Else return type is Void if it does not exist
|
// Else return type is Void if it does not exist
|
||||||
TypeKind::Void
|
TypeKind::Void
|
||||||
};
|
};
|
||||||
let then_ret_t = then_ret_t;
|
let then_ret_t = if then_ret_kind == ReturnKind::Hard {
|
||||||
|
TypeKind::Void
|
||||||
|
} else {
|
||||||
|
then_ret_t
|
||||||
|
};
|
||||||
|
|
||||||
// Make sure then and else -blocks have the same return type
|
// Make sure then and else -blocks have the same return type
|
||||||
let collapsed = then_ret_t
|
let collapsed = then_ret_t
|
||||||
.collapse_into(&else_ret_t)
|
.collapse_into(&else_ret_t)
|
||||||
.or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?;
|
.or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?;
|
||||||
|
|
||||||
if let Some(rhs) = rhs.as_mut() {
|
if let Some(rhs) = rhs {
|
||||||
// If rhs existed, typecheck both sides to perform type
|
// If rhs existed, typecheck both sides to perform type
|
||||||
// coercion.
|
// coercion.
|
||||||
let lhs_res = lhs.typecheck(state, &typerefs, Some(&collapsed));
|
let lhs_res = lhs.typecheck(state, &typerefs, Some(&collapsed));
|
||||||
let rhs_res = rhs.typecheck(state, &typerefs, Some(&collapsed));
|
let rhs_res = rhs.typecheck(state, &typerefs, Some(&collapsed));
|
||||||
state.ok(lhs_res, lhs.1);
|
state.ok(lhs_res, lhs.meta);
|
||||||
state.ok(rhs_res, rhs.1);
|
state.ok(rhs_res, rhs.meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(collapsed)
|
Ok(collapsed)
|
||||||
|
@ -227,26 +227,22 @@ impl Expression {
|
|||||||
let lhs_res = lhs.infer_types(state, type_refs);
|
let lhs_res = lhs.infer_types(state, type_refs);
|
||||||
let lhs_hints = state.ok(lhs_res, cond.1);
|
let lhs_hints = state.ok(lhs_res, cond.1);
|
||||||
|
|
||||||
if let Some(rhs) = rhs.as_mut() {
|
if let Some(rhs) = rhs {
|
||||||
// Infer RHS return type
|
// Infer RHS return type
|
||||||
let rhs_res = rhs.infer_types(state, type_refs);
|
let rhs_res = rhs.infer_types(state, type_refs);
|
||||||
let rhs_hints = state.ok(rhs_res, cond.1);
|
let rhs_hints = state.ok(rhs_res, cond.1);
|
||||||
|
|
||||||
// Narrow LHS to the same type as RHS and return it's return type
|
// Narrow LHS to the same type as RHS and return it's return type
|
||||||
if let (Some(mut lhs_hints), Some(mut rhs_hints)) = (lhs_hints, rhs_hints) {
|
if let (Some(mut lhs_hints), Some(mut rhs_hints)) = (lhs_hints, rhs_hints) {
|
||||||
lhs_hints
|
lhs_hints.1.narrow(&mut rhs_hints.1);
|
||||||
.narrow(&mut rhs_hints)
|
Ok(pick_return(lhs_hints, rhs_hints).1)
|
||||||
.ok_or(ErrorKind::TypesIncompatible(
|
|
||||||
lhs_hints.resolve_deep().unwrap(),
|
|
||||||
rhs_hints.resolve_deep().unwrap(),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
// Failed to retrieve types from either
|
// Failed to retrieve types from either
|
||||||
Ok(type_refs.from_type(&Vague(Unknown)).unwrap())
|
Ok(type_refs.from_type(&Vague(Unknown)).unwrap())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Return LHS return type
|
// Return LHS return type
|
||||||
if let Some(type_ref) = lhs_hints {
|
if let Some((_, type_ref)) = lhs_hints {
|
||||||
Ok(type_ref)
|
Ok(type_ref)
|
||||||
} else {
|
} else {
|
||||||
Ok(type_refs.from_type(&Vague(Unknown)).unwrap())
|
Ok(type_refs.from_type(&Vague(Unknown)).unwrap())
|
||||||
|
@ -166,6 +166,8 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
|
|
||||||
match T::parse(clone) {
|
match T::parse(clone) {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
// dbg!(&res);
|
||||||
let new_pos = ref_pos.max(self.position);
|
let new_pos = ref_pos.max(self.position);
|
||||||
Ok((res, new_pos))
|
Ok((res, new_pos))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user