forked from AbleOS/holey-bytes
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])) {
|
fn encode(&mut self, (len, instr): (usize, [u8; instrs::MAX_SIZE])) {
|
||||||
// let name = instrs::NAMES[instr[0] as usize];
|
let name = instrs::NAMES[instr[0] as usize];
|
||||||
// println!(
|
println!(
|
||||||
// "{}: {}",
|
"{:08x}: {}: {}",
|
||||||
// name,
|
self.code.len(),
|
||||||
// instr
|
name,
|
||||||
// .iter()
|
instr
|
||||||
// .take(len)
|
.iter()
|
||||||
// .skip(1)
|
.take(len)
|
||||||
// .map(|b| format!("{:02x}", b))
|
.skip(1)
|
||||||
// .collect::<String>()
|
.map(|b| format!("{:02x}", b))
|
||||||
// );
|
.collect::<String>()
|
||||||
|
);
|
||||||
self.code.extend_from_slice(&instr[..len]);
|
self.code.extend_from_slice(&instr[..len]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,22 +368,47 @@ impl<'a> Codegen<'a> {
|
||||||
ty: expeted.unwrap_or(Expr::Ident { name: "int" }),
|
ty: expeted.unwrap_or(Expr::Ident { name: "int" }),
|
||||||
loc: Loc::Imm(value),
|
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 } => {
|
E::BinOp { left, op, right } => {
|
||||||
let left = self.expr(left, expeted).unwrap();
|
let left = self.expr(left, expeted).unwrap();
|
||||||
let right = self.expr(right, Some(left.ty)).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 {
|
let op = match op {
|
||||||
T::Plus => instrs::add64,
|
T::Plus => instrs::add64,
|
||||||
T::Minus => instrs::sub64,
|
T::Minus => instrs::sub64,
|
||||||
T::Star => instrs::mul64,
|
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::FSlash => |reg0, reg1, reg2| instrs::diru64(reg0, ZERO, reg1, reg2),
|
||||||
T::Assign => return self.assign(left, right),
|
T::Assign => return self.assign(left, right),
|
||||||
_ => unimplemented!("{:#?}", op),
|
_ => 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.code.encode(op(lhs, lhs, rhs));
|
||||||
self.gpa.free(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<()> {
|
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.prelude(self.get_label("main"));
|
||||||
self.temp
|
self.temp
|
||||||
.relocate(&self.labels, self.temp.code.len() as i64);
|
.relocate(&self.labels, self.temp.code.len() as i64);
|
||||||
|
@ -501,6 +525,7 @@ pub struct Value<'a> {
|
||||||
loc: Loc,
|
loc: Loc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum Loc {
|
pub enum Loc {
|
||||||
Reg(Reg),
|
Reg(Reg),
|
||||||
Imm(u64),
|
Imm(u64),
|
||||||
|
@ -578,6 +603,7 @@ mod tests {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
codegen.dump(&mut out).unwrap();
|
codegen.dump(&mut out).unwrap();
|
||||||
|
|
||||||
|
std::fs::write("test.bin", &out).unwrap();
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
let mut stack = [0_u64; 1024];
|
let mut stack = [0_u64; 1024];
|
||||||
|
@ -608,5 +634,6 @@ mod tests {
|
||||||
arithmetic => include_str!("../examples/arithmetic.hb");
|
arithmetic => include_str!("../examples/arithmetic.hb");
|
||||||
variables => include_str!("../examples/variables.hb");
|
variables => include_str!("../examples/variables.hb");
|
||||||
functions => include_str!("../examples/functions.hb");
|
functions => include_str!("../examples/functions.hb");
|
||||||
|
if_statements => include_str!("../examples/if_statement.hb");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,12 @@ pub enum TokenKind {
|
||||||
FSlash,
|
FSlash,
|
||||||
Bor,
|
Bor,
|
||||||
Or,
|
Or,
|
||||||
|
Le,
|
||||||
Semi,
|
Semi,
|
||||||
Colon,
|
Colon,
|
||||||
Comma,
|
Comma,
|
||||||
Return,
|
Return,
|
||||||
|
If,
|
||||||
Eof,
|
Eof,
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
@ -57,10 +59,12 @@ impl std::fmt::Display for TokenKind {
|
||||||
T::FSlash => "/",
|
T::FSlash => "/",
|
||||||
T::Bor => "|",
|
T::Bor => "|",
|
||||||
T::Or => "||",
|
T::Or => "||",
|
||||||
|
T::Le => "<=",
|
||||||
T::Semi => ";",
|
T::Semi => ";",
|
||||||
T::Colon => ":",
|
T::Colon => ":",
|
||||||
T::Comma => ",",
|
T::Comma => ",",
|
||||||
T::Return => "return",
|
T::Return => "return",
|
||||||
|
T::If => "if",
|
||||||
T::Eof => "<eof>",
|
T::Eof => "<eof>",
|
||||||
T::Error => "<error>",
|
T::Error => "<error>",
|
||||||
};
|
};
|
||||||
|
@ -72,8 +76,9 @@ impl TokenKind {
|
||||||
pub fn precedence(&self) -> Option<u8> {
|
pub fn precedence(&self) -> Option<u8> {
|
||||||
Some(match self {
|
Some(match self {
|
||||||
Self::Assign => 1,
|
Self::Assign => 1,
|
||||||
Self::Plus | Self::Minus => 2,
|
Self::Le => 21,
|
||||||
Self::Star | Self::FSlash => 3,
|
Self::Plus | Self::Minus => 23,
|
||||||
|
Self::Star | Self::FSlash => 24,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -161,6 +166,7 @@ impl<'a> Iterator for Lexer<'a> {
|
||||||
let ident = &self.bytes[start as usize..self.pos as usize];
|
let ident = &self.bytes[start as usize..self.pos as usize];
|
||||||
match ident {
|
match ident {
|
||||||
b"return" => T::Return,
|
b"return" => T::Return,
|
||||||
|
b"if" => T::If,
|
||||||
_ => T::Ident,
|
_ => T::Ident,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,6 +177,10 @@ impl<'a> Iterator for Lexer<'a> {
|
||||||
b',' => T::Comma,
|
b',' => T::Comma,
|
||||||
b';' => T::Semi,
|
b';' => T::Semi,
|
||||||
b'=' => T::Assign,
|
b'=' => T::Assign,
|
||||||
|
b'<' => match self.advance_if(b'=') {
|
||||||
|
true => T::Le,
|
||||||
|
false => T::Error,
|
||||||
|
},
|
||||||
b'+' => T::Plus,
|
b'+' => T::Plus,
|
||||||
b'-' => T::Minus,
|
b'-' => T::Minus,
|
||||||
b'*' => T::Star,
|
b'*' => T::Star,
|
||||||
|
|
|
@ -2,9 +2,6 @@ use std::{cell::Cell, ops::Not, ptr::NonNull};
|
||||||
|
|
||||||
use crate::lexer::{Lexer, Token, TokenKind};
|
use crate::lexer::{Lexer, Token, TokenKind};
|
||||||
|
|
||||||
type Ptr<'a, T> = &'a T;
|
|
||||||
type Slice<'a, T> = &'a [T];
|
|
||||||
|
|
||||||
pub struct Parser<'a, 'b> {
|
pub struct Parser<'a, 'b> {
|
||||||
path: &'a std::path::Path,
|
path: &'a std::path::Path,
|
||||||
lexer: Lexer<'a>,
|
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()))
|
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())
|
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())
|
self.arena.alloc(self.expr())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +81,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
Expr::Ident { name }
|
Expr::Ident { name }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TokenKind::If => {
|
||||||
|
let cond = self.ptr_expr();
|
||||||
|
let then = self.ptr_expr();
|
||||||
|
Expr::If { cond, then }
|
||||||
|
}
|
||||||
TokenKind::Return => Expr::Return {
|
TokenKind::Return => Expr::Return {
|
||||||
val: (self.token.kind != TokenKind::Semi).then(|| self.ptr_expr()),
|
val: (self.token.kind != TokenKind::Semi).then(|| self.ptr_expr()),
|
||||||
},
|
},
|
||||||
|
@ -154,7 +156,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
expr
|
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<_>>();
|
let vec = std::iter::from_fn(|| f(self)).collect::<Vec<_>>();
|
||||||
self.arena.alloc_slice(&vec)
|
self.arena.alloc_slice(&vec)
|
||||||
}
|
}
|
||||||
|
@ -188,34 +190,38 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Expr<'a> {
|
pub enum Expr<'a> {
|
||||||
Decl {
|
Decl {
|
||||||
name: Ptr<'a, str>,
|
name: &'a str,
|
||||||
val: Ptr<'a, Expr<'a>>,
|
val: &'a Expr<'a>,
|
||||||
},
|
},
|
||||||
Closure {
|
Closure {
|
||||||
args: Slice<'a, (Ptr<'a, str>, Expr<'a>)>,
|
args: &'a [(&'a str, Expr<'a>)],
|
||||||
ret: Ptr<'a, Expr<'a>>,
|
ret: &'a Expr<'a>,
|
||||||
body: Ptr<'a, Expr<'a>>,
|
body: &'a Expr<'a>,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
func: Ptr<'a, Expr<'a>>,
|
func: &'a Expr<'a>,
|
||||||
args: Slice<'a, Expr<'a>>,
|
args: &'a [Expr<'a>],
|
||||||
},
|
},
|
||||||
Return {
|
Return {
|
||||||
val: Option<Ptr<'a, Expr<'a>>>,
|
val: Option<&'a Expr<'a>>,
|
||||||
},
|
},
|
||||||
Ident {
|
Ident {
|
||||||
name: Ptr<'a, str>,
|
name: &'a str,
|
||||||
},
|
},
|
||||||
Block {
|
Block {
|
||||||
stmts: Slice<'a, Expr<'a>>,
|
stmts: &'a [Expr<'a>],
|
||||||
},
|
},
|
||||||
Number {
|
Number {
|
||||||
value: u64,
|
value: u64,
|
||||||
},
|
},
|
||||||
BinOp {
|
BinOp {
|
||||||
left: Ptr<'a, Expr<'a>>,
|
left: &'a Expr<'a>,
|
||||||
op: TokenKind,
|
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 {
|
match *self {
|
||||||
|
Self::If { cond, then } => write!(f, "if {} {}", cond, then),
|
||||||
Self::Decl { name, val } => write!(f, "{} := {}", name, val),
|
Self::Decl { name, val } => write!(f, "{} := {}", name, val),
|
||||||
Self::Closure { ret, body, args } => {
|
Self::Closure { ret, body, args } => {
|
||||||
write!(f, "|")?;
|
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