making if statements without else branch work
This commit is contained in:
parent
1d74f27b0e
commit
7f32e7775c
11
hblang/examples/if_statement.hb
Normal file
11
hblang/examples/if_statement.hb
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
main := ||: int {
|
||||
return fib(10);
|
||||
}
|
||||
|
||||
fib := |x: int|: int {
|
||||
if x <= 2 {
|
||||
return 1;
|
||||
}
|
||||
return fib(x - 1) + fib(x - 2);
|
||||
}
|
|
@ -54,17 +54,18 @@ impl Func {
|
|||
}
|
||||
|
||||
fn encode(&mut self, (len, instr): (usize, [u8; instrs::MAX_SIZE])) {
|
||||
// let name = instrs::NAMES[instr[0] as usize];
|
||||
// println!(
|
||||
// "{}: {}",
|
||||
// name,
|
||||
// instr
|
||||
// .iter()
|
||||
// .take(len)
|
||||
// .skip(1)
|
||||
// .map(|b| format!("{:02x}", b))
|
||||
// .collect::<String>()
|
||||
// );
|
||||
let name = instrs::NAMES[instr[0] as usize];
|
||||
println!(
|
||||
"{:08x}: {}: {}",
|
||||
self.code.len(),
|
||||
name,
|
||||
instr
|
||||
.iter()
|
||||
.take(len)
|
||||
.skip(1)
|
||||
.map(|b| format!("{:02x}", b))
|
||||
.collect::<String>()
|
||||
);
|
||||
self.code.extend_from_slice(&instr[..len]);
|
||||
}
|
||||
|
||||
|
@ -367,22 +368,47 @@ impl<'a> Codegen<'a> {
|
|||
ty: expeted.unwrap_or(Expr::Ident { name: "int" }),
|
||||
loc: Loc::Imm(value),
|
||||
}),
|
||||
E::If { cond, then } => {
|
||||
let cond = self.expr(cond, Some(Expr::Ident { name: "bool" })).unwrap();
|
||||
let reg = self.loc_to_reg(cond.loc);
|
||||
let jump_offset = self.code.code.len() as u32;
|
||||
println!("jump_offset: {:02x}", jump_offset);
|
||||
self.code.encode(instrs::jeq(reg, 0, 0));
|
||||
self.gpa.free(reg);
|
||||
|
||||
self.expr(then, None);
|
||||
let jump = self.code.code.len() as i16 - jump_offset as i16;
|
||||
println!("jump: {:02x}", jump);
|
||||
self.code.code[jump_offset as usize + 3..][..2]
|
||||
.copy_from_slice(&jump.to_ne_bytes());
|
||||
|
||||
None
|
||||
}
|
||||
E::BinOp { left, op, right } => {
|
||||
let left = self.expr(left, expeted).unwrap();
|
||||
let right = self.expr(right, Some(left.ty)).unwrap();
|
||||
|
||||
let lhs = self.loc_to_reg(left.loc);
|
||||
let rhs = self.loc_to_reg(right.loc);
|
||||
|
||||
let op = match op {
|
||||
T::Plus => instrs::add64,
|
||||
T::Minus => instrs::sub64,
|
||||
T::Star => instrs::mul64,
|
||||
T::Le => {
|
||||
self.code.encode(instrs::cmpu(lhs, lhs, rhs));
|
||||
self.gpa.free(rhs);
|
||||
self.code.encode(instrs::cmpui(lhs, lhs, 1));
|
||||
return Some(Value {
|
||||
ty: Expr::Ident { name: "bool" },
|
||||
loc: Loc::Reg(lhs),
|
||||
});
|
||||
}
|
||||
T::FSlash => |reg0, reg1, reg2| instrs::diru64(reg0, ZERO, reg1, reg2),
|
||||
T::Assign => return self.assign(left, right),
|
||||
_ => unimplemented!("{:#?}", op),
|
||||
};
|
||||
|
||||
let lhs = self.loc_to_reg(left.loc);
|
||||
let rhs = self.loc_to_reg(right.loc);
|
||||
|
||||
self.code.encode(op(lhs, lhs, rhs));
|
||||
self.gpa.free(rhs);
|
||||
|
||||
|
@ -476,8 +502,6 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
pub fn dump(mut self, out: &mut impl std::io::Write) -> std::io::Result<()> {
|
||||
assert!(self.labels.iter().filter(|l| l.offset == 0).count() == 1);
|
||||
|
||||
self.temp.prelude(self.get_label("main"));
|
||||
self.temp
|
||||
.relocate(&self.labels, self.temp.code.len() as i64);
|
||||
|
@ -501,6 +525,7 @@ pub struct Value<'a> {
|
|||
loc: Loc,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Loc {
|
||||
Reg(Reg),
|
||||
Imm(u64),
|
||||
|
@ -578,6 +603,7 @@ mod tests {
|
|||
let mut out = Vec::new();
|
||||
codegen.dump(&mut out).unwrap();
|
||||
|
||||
std::fs::write("test.bin", &out).unwrap();
|
||||
use std::fmt::Write;
|
||||
|
||||
let mut stack = [0_u64; 1024];
|
||||
|
@ -608,5 +634,6 @@ mod tests {
|
|||
arithmetic => include_str!("../examples/arithmetic.hb");
|
||||
variables => include_str!("../examples/variables.hb");
|
||||
functions => include_str!("../examples/functions.hb");
|
||||
if_statements => include_str!("../examples/if_statement.hb");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,10 +29,12 @@ pub enum TokenKind {
|
|||
FSlash,
|
||||
Bor,
|
||||
Or,
|
||||
Le,
|
||||
Semi,
|
||||
Colon,
|
||||
Comma,
|
||||
Return,
|
||||
If,
|
||||
Eof,
|
||||
Error,
|
||||
}
|
||||
|
@ -57,10 +59,12 @@ impl std::fmt::Display for TokenKind {
|
|||
T::FSlash => "/",
|
||||
T::Bor => "|",
|
||||
T::Or => "||",
|
||||
T::Le => "<=",
|
||||
T::Semi => ";",
|
||||
T::Colon => ":",
|
||||
T::Comma => ",",
|
||||
T::Return => "return",
|
||||
T::If => "if",
|
||||
T::Eof => "<eof>",
|
||||
T::Error => "<error>",
|
||||
};
|
||||
|
@ -72,8 +76,9 @@ impl TokenKind {
|
|||
pub fn precedence(&self) -> Option<u8> {
|
||||
Some(match self {
|
||||
Self::Assign => 1,
|
||||
Self::Plus | Self::Minus => 2,
|
||||
Self::Star | Self::FSlash => 3,
|
||||
Self::Le => 21,
|
||||
Self::Plus | Self::Minus => 23,
|
||||
Self::Star | Self::FSlash => 24,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
@ -161,6 +166,7 @@ impl<'a> Iterator for Lexer<'a> {
|
|||
let ident = &self.bytes[start as usize..self.pos as usize];
|
||||
match ident {
|
||||
b"return" => T::Return,
|
||||
b"if" => T::If,
|
||||
_ => T::Ident,
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +177,10 @@ impl<'a> Iterator for Lexer<'a> {
|
|||
b',' => T::Comma,
|
||||
b';' => T::Semi,
|
||||
b'=' => T::Assign,
|
||||
b'<' => match self.advance_if(b'=') {
|
||||
true => T::Le,
|
||||
false => T::Error,
|
||||
},
|
||||
b'+' => T::Plus,
|
||||
b'-' => T::Minus,
|
||||
b'*' => T::Star,
|
||||
|
|
|
@ -2,9 +2,6 @@ use std::{cell::Cell, ops::Not, ptr::NonNull};
|
|||
|
||||
use crate::lexer::{Lexer, Token, TokenKind};
|
||||
|
||||
type Ptr<'a, T> = &'a T;
|
||||
type Slice<'a, T> = &'a [T];
|
||||
|
||||
pub struct Parser<'a, 'b> {
|
||||
path: &'a std::path::Path,
|
||||
lexer: Lexer<'a>,
|
||||
|
@ -32,7 +29,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn file(&mut self) -> Slice<'a, Expr<'a>> {
|
||||
pub fn file(&mut self) -> &'a [Expr<'a>] {
|
||||
self.collect(|s| (s.token.kind != TokenKind::Eof).then(|| s.expr()))
|
||||
}
|
||||
|
||||
|
@ -40,7 +37,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
std::mem::replace(&mut self.token, self.lexer.next())
|
||||
}
|
||||
|
||||
fn ptr_expr(&mut self) -> Ptr<'a, Expr<'a>> {
|
||||
fn ptr_expr(&mut self) -> &'a Expr<'a> {
|
||||
self.arena.alloc(self.expr())
|
||||
}
|
||||
|
||||
|
@ -84,6 +81,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
Expr::Ident { name }
|
||||
}
|
||||
}
|
||||
TokenKind::If => {
|
||||
let cond = self.ptr_expr();
|
||||
let then = self.ptr_expr();
|
||||
Expr::If { cond, then }
|
||||
}
|
||||
TokenKind::Return => Expr::Return {
|
||||
val: (self.token.kind != TokenKind::Semi).then(|| self.ptr_expr()),
|
||||
},
|
||||
|
@ -154,7 +156,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
expr
|
||||
}
|
||||
|
||||
fn collect<T: Copy>(&mut self, mut f: impl FnMut(&mut Self) -> Option<T>) -> Slice<'a, T> {
|
||||
fn collect<T: Copy>(&mut self, mut f: impl FnMut(&mut Self) -> Option<T>) -> &'a [T] {
|
||||
let vec = std::iter::from_fn(|| f(self)).collect::<Vec<_>>();
|
||||
self.arena.alloc_slice(&vec)
|
||||
}
|
||||
|
@ -188,34 +190,38 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Expr<'a> {
|
||||
Decl {
|
||||
name: Ptr<'a, str>,
|
||||
val: Ptr<'a, Expr<'a>>,
|
||||
name: &'a str,
|
||||
val: &'a Expr<'a>,
|
||||
},
|
||||
Closure {
|
||||
args: Slice<'a, (Ptr<'a, str>, Expr<'a>)>,
|
||||
ret: Ptr<'a, Expr<'a>>,
|
||||
body: Ptr<'a, Expr<'a>>,
|
||||
args: &'a [(&'a str, Expr<'a>)],
|
||||
ret: &'a Expr<'a>,
|
||||
body: &'a Expr<'a>,
|
||||
},
|
||||
Call {
|
||||
func: Ptr<'a, Expr<'a>>,
|
||||
args: Slice<'a, Expr<'a>>,
|
||||
func: &'a Expr<'a>,
|
||||
args: &'a [Expr<'a>],
|
||||
},
|
||||
Return {
|
||||
val: Option<Ptr<'a, Expr<'a>>>,
|
||||
val: Option<&'a Expr<'a>>,
|
||||
},
|
||||
Ident {
|
||||
name: Ptr<'a, str>,
|
||||
name: &'a str,
|
||||
},
|
||||
Block {
|
||||
stmts: Slice<'a, Expr<'a>>,
|
||||
stmts: &'a [Expr<'a>],
|
||||
},
|
||||
Number {
|
||||
value: u64,
|
||||
},
|
||||
BinOp {
|
||||
left: Ptr<'a, Expr<'a>>,
|
||||
left: &'a Expr<'a>,
|
||||
op: TokenKind,
|
||||
right: Ptr<'a, Expr<'a>>,
|
||||
right: &'a Expr<'a>,
|
||||
},
|
||||
If {
|
||||
cond: &'a Expr<'a>,
|
||||
then: &'a Expr<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -226,6 +232,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
|||
}
|
||||
|
||||
match *self {
|
||||
Self::If { cond, then } => write!(f, "if {} {}", cond, then),
|
||||
Self::Decl { name, val } => write!(f, "{} := {}", name, val),
|
||||
Self::Closure { ret, body, args } => {
|
||||
write!(f, "|")?;
|
||||
|
|
BIN
hblang/test.bin
Normal file
BIN
hblang/test.bin
Normal file
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
ret: 33
|
||||
status: Ok(())
|
Loading…
Reference in a new issue