diff --git a/Makefile b/Makefile index 6c323ca..de80121 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ BIN=$(SRC:.reid=.out) REID=cargo run --example cli LD=ld -LDFLAGS= +LDFLAGS=-lSDL3 all: $(BIN) clean: diff --git a/graphics.reid b/graphics.reid new file mode 100644 index 0000000..cf115b9 --- /dev/null +++ b/graphics.reid @@ -0,0 +1,153 @@ +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; +} diff --git a/reid-llvm-lib/src/lib.rs b/reid-llvm-lib/src/lib.rs index c8eadc2..c41268b 100644 --- a/reid-llvm-lib/src/lib.rs +++ b/reid-llvm-lib/src/lib.rs @@ -199,6 +199,7 @@ pub struct BlockData { deleted: bool, } +#[derive(Clone)] pub struct Block<'builder> { phantom: PhantomData<&'builder ()>, builder: Builder, diff --git a/reid/Cargo.toml b/reid/Cargo.toml index 5859397..b242321 100644 --- a/reid/Cargo.toml +++ b/reid/Cargo.toml @@ -14,6 +14,6 @@ color = ["colored"] [dependencies] ## Make it easier to generate errors thiserror = "1.0.44" -reid-lib = { path = "../reid-llvm-lib", version = "0.1.0"} +reid-lib = { path = "../reid-llvm-lib", version = "0.1.0" } colored = {version = "3.0.0", optional = true} \ No newline at end of file diff --git a/reid/lib/std.reid b/reid/lib/std.reid index 21e7158..ae3e13a 100644 --- a/reid/lib/std.reid +++ b/reid/lib/std.reid @@ -94,13 +94,13 @@ fn str_length(string: *char, position: u32) -> u32 { pub fn add_num_to_str(string: &mut String, num: u64) { if num == 0 { add_char(string, '0'); } - else { if num == 1 { add_char(string, '1'); } - else { if num == 2 { add_char(string, '2'); } - else { if num == 3 { add_char(string, '3'); } - else { if num == 4 { add_char(string, '4'); } - else { if num == 5 { add_char(string, '5'); } - else { if num == 6 { add_char(string, '6'); } - else { if num == 7 { add_char(string, '7'); } - else { if num == 8 { add_char(string, '8'); } - else { if num == 9 { add_char(string, '9'); } } } } } } } } } } + else if num == 1 { add_char(string, '1'); } + else if num == 2 { add_char(string, '2'); } + else if num == 3 { add_char(string, '3'); } + else if num == 4 { add_char(string, '4'); } + else if num == 5 { add_char(string, '5'); } + else if num == 6 { add_char(string, '6'); } + else if num == 7 { add_char(string, '7'); } + else if num == 8 { add_char(string, '8'); } + else if num == 9 { add_char(string, '9'); } } \ No newline at end of file diff --git a/reid/src/codegen.rs b/reid/src/codegen.rs index 4f1f66f..afc0d85 100644 --- a/reid/src/codegen.rs +++ b/reid/src/codegen.rs @@ -746,16 +746,19 @@ impl mir::Expression { } mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state), mir::ExprKind::Block(block) => { - let mut inner_scope = scope.with_block(scope.function.ir.block("inner")); - if let Some(ret) = block.codegen(&mut inner_scope, state) { - inner_scope - .block - .terminate(Term::Br(scope.block.value())) - .unwrap(); + let inner = scope.function.ir.block("inner"); + scope.block.terminate(Term::Br(inner.value())).unwrap(); + + let mut inner_scope = scope.with_block(inner); + let ret = if let Some(ret) = block.codegen(&mut inner_scope, state) { Some(ret) } else { 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) => { let StackValue(kind, ty) = expression @@ -1138,19 +1141,12 @@ impl mir::IfExpression { let before_v = debug.info.location(&debug.scope, before_location); scope.block.set_terminator_location(before_v).ok(); - let then_location = self - .1 - .return_meta() - .into_debug(scope.tokens, debug.scope) - .unwrap(); + let then_location = self.1 .1.into_debug(scope.tokens, debug.scope).unwrap(); let then_v = debug.info.location(&debug.scope, then_location); then_b.set_terminator_location(then_v).unwrap(); - let else_location = if let Some(else_block) = &self.2 { - else_block - .return_meta() - .into_debug(scope.tokens, debug.scope) - .unwrap() + let else_location = if let Some(else_expr) = self.2.as_ref() { + else_expr.1.into_debug(scope.tokens, debug.scope).unwrap() } else { then_location }; @@ -1168,7 +1164,7 @@ impl mir::IfExpression { let then_res = self.1.codegen(&mut then_scope, state); then_scope.block.terminate(Term::Br(after_bb)).ok(); - let else_res = if let Some(else_block) = &self.2 { + let else_res = if let Some(else_expr) = self.2.as_ref() { let mut else_scope = scope.with_block(else_b); scope @@ -1176,7 +1172,7 @@ impl mir::IfExpression { .terminate(Term::CondBr(condition.instr(), then_bb, else_bb)) .unwrap(); - let opt = else_block.codegen(&mut else_scope, state); + let opt = else_expr.codegen(&mut else_scope, state); else_scope.block.terminate(Term::Br(after_bb)).ok(); diff --git a/reid/src/lexer.rs b/reid/src/lexer.rs index 03f0e47..3689b22 100644 --- a/reid/src/lexer.rs +++ b/reid/src/lexer.rs @@ -275,7 +275,7 @@ pub fn tokenize>(to_tokenize: T) -> Result, Error match character { '\'' => Token::CharLit(value), '\"' => Token::StringLit(value), - _ => unsafe { unreachable_unchecked() }, + _ => unreachable!(), } } // "words" diff --git a/reid/src/mir/fmt.rs b/reid/src/mir/fmt.rs index 6944120..89f2b95 100644 --- a/reid/src/mir/fmt.rs +++ b/reid/src/mir/fmt.rs @@ -240,7 +240,7 @@ impl Display for IfExpression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "if {} ", self.0)?; Display::fmt(&self.1, f)?; - if let Some(e) = *self.2 { + if let Some(e) = self.2.as_ref() { Display::fmt(&e, f)?; } Ok(()) diff --git a/reid/src/mir/implement.rs b/reid/src/mir/implement.rs index d0d8fd3..5f91f5b 100644 --- a/reid/src/mir/implement.rs +++ b/reid/src/mir/implement.rs @@ -491,8 +491,8 @@ impl IfExpression { mod_id: SourceModuleId, ) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> { let then_r = self.1.return_type(refs, mod_id)?; - if let Some(else_b) = &self.2 { - let else_r = else_b.return_type(refs, mod_id)?; + if let Some(else_e) = self.2.as_ref() { + let else_r = else_e.return_type(refs, mod_id)?; let kind = if then_r.0 == ReturnKind::Hard && else_r.0 == ReturnKind::Hard { ReturnKind::Hard diff --git a/reid/src/mir/typecheck.rs b/reid/src/mir/typecheck.rs index 3e5e5e6..655a927 100644 --- a/reid/src/mir/typecheck.rs +++ b/reid/src/mir/typecheck.rs @@ -491,46 +491,31 @@ impl Expression { // Typecheck then/else return types and make sure they are the // same, if else exists. let then_res = lhs.typecheck(state, &typerefs, hint_t); - let (then_ret_kind, then_ret_t) = state.or_else( - then_res, - (ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)), - lhs.meta, - ); - 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, - ); + let then_ret_t = state.or_else(then_res, TypeKind::Vague(Vague::Unknown), lhs.1); + let else_ret_t = if let Some(else_expr) = rhs.as_mut() { + let res = else_expr.typecheck(state, &typerefs, hint_t); + let else_ret_t = + state.or_else(res, TypeKind::Vague(Vague::Unknown), else_expr.1); - if else_ret_kind == ReturnKind::Hard { - TypeKind::Void - } else { - else_ret_t - } + else_ret_t } else { // Else return type is Void if it does not exist TypeKind::Void }; - let then_ret_t = if then_ret_kind == ReturnKind::Hard { - TypeKind::Void - } else { - then_ret_t - }; + let then_ret_t = then_ret_t; // Make sure then and else -blocks have the same return type let collapsed = then_ret_t .collapse_into(&else_ret_t) .or(Err(ErrorKind::BranchTypesDiffer(then_ret_t, else_ret_t)))?; - if let Some(rhs) = rhs { + if let Some(rhs) = rhs.as_mut() { // If rhs existed, typecheck both sides to perform type // coercion. let lhs_res = lhs.typecheck(state, &typerefs, Some(&collapsed)); let rhs_res = rhs.typecheck(state, &typerefs, Some(&collapsed)); - state.ok(lhs_res, lhs.meta); - state.ok(rhs_res, rhs.meta); + state.ok(lhs_res, lhs.1); + state.ok(rhs_res, rhs.1); } Ok(collapsed) diff --git a/reid/src/mir/typeinference.rs b/reid/src/mir/typeinference.rs index c109879..9054416 100644 --- a/reid/src/mir/typeinference.rs +++ b/reid/src/mir/typeinference.rs @@ -227,22 +227,26 @@ impl Expression { let lhs_res = lhs.infer_types(state, type_refs); let lhs_hints = state.ok(lhs_res, cond.1); - if let Some(rhs) = rhs { + if let Some(rhs) = rhs.as_mut() { // Infer RHS return type let rhs_res = rhs.infer_types(state, type_refs); let rhs_hints = state.ok(rhs_res, cond.1); // Narrow LHS to the same type as RHS and return it's return type if let (Some(mut lhs_hints), Some(mut rhs_hints)) = (lhs_hints, rhs_hints) { - lhs_hints.1.narrow(&mut rhs_hints.1); - Ok(pick_return(lhs_hints, rhs_hints).1) + lhs_hints + .narrow(&mut rhs_hints) + .ok_or(ErrorKind::TypesIncompatible( + lhs_hints.resolve_deep().unwrap(), + rhs_hints.resolve_deep().unwrap(), + )) } else { // Failed to retrieve types from either Ok(type_refs.from_type(&Vague(Unknown)).unwrap()) } } else { // Return LHS return type - if let Some((_, type_ref)) = lhs_hints { + if let Some(type_ref) = lhs_hints { Ok(type_ref) } else { Ok(type_refs.from_type(&Vague(Unknown)).unwrap()) diff --git a/reid/src/token_stream.rs b/reid/src/token_stream.rs index 006ab0b..1d6043f 100644 --- a/reid/src/token_stream.rs +++ b/reid/src/token_stream.rs @@ -166,8 +166,6 @@ impl<'a, 'b> TokenStream<'a, 'b> { match T::parse(clone) { Ok(res) => { - #[cfg(debug_assertions)] - // dbg!(&res); let new_pos = ref_pos.max(self.position); Ok((res, new_pos)) }