forked from AbleOS/holey-bytes
now compiling some trivial arithmetic
This commit is contained in:
parent
81952cfc40
commit
cf99091a45
|
@ -1,3 +1,3 @@
|
|||
main := ||: int {
|
||||
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4;
|
||||
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use {
|
||||
crate::parser::{self, Expr},
|
||||
crate::{
|
||||
lexer,
|
||||
parser::{self, Expr},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
|
@ -66,6 +69,10 @@ impl Func {
|
|||
self.tx();
|
||||
}
|
||||
|
||||
fn div64(&mut self, reg0: Reg, reg1: Reg, reg2: Reg) {
|
||||
self.diru64(reg0, ZERO, reg1, reg2);
|
||||
}
|
||||
|
||||
fn relocate(&mut self, labels: &[Label], shift: i64) {
|
||||
for reloc in self.relocs.drain(..) {
|
||||
let label = &labels[reloc.id as usize];
|
||||
|
@ -158,13 +165,14 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
fn expr(&mut self, expr: &'a parser::Expr<'a>, expeted: Option<Expr<'a>>) -> Option<Value<'a>> {
|
||||
use parser::Expr as E;
|
||||
use {lexer::TokenKind as T, parser::Expr as E};
|
||||
match *expr {
|
||||
E::Decl {
|
||||
name,
|
||||
val: E::Closure { ret, body },
|
||||
} => {
|
||||
let frame = self.add_label(name);
|
||||
self.gpa.init_caller();
|
||||
self.ret = **ret;
|
||||
self.expr(body, None);
|
||||
self.write_fn_prelude(frame);
|
||||
|
@ -194,7 +202,48 @@ impl<'a> Codegen<'a> {
|
|||
ty: expeted.unwrap_or(Expr::Ident { name: "int" }),
|
||||
loc: Loc::Imm(value),
|
||||
}),
|
||||
ast => unimplemented!("{:?}", ast),
|
||||
E::BinOp { left, op, right } => {
|
||||
let left = self.expr(left, expeted).unwrap();
|
||||
let right = self.expr(right, Some(left.ty)).unwrap();
|
||||
|
||||
type Op = fn(&mut Func, u8, u8, u8);
|
||||
type ImmOp = fn(&mut Func, u8, u8, u64);
|
||||
|
||||
let op = match op {
|
||||
T::Plus => Func::add64 as Op,
|
||||
T::Minus => Func::sub64 as Op,
|
||||
T::Star => Func::mul64 as Op,
|
||||
T::FSlash => Func::div64 as Op,
|
||||
_ => unimplemented!("{:#?}", op),
|
||||
};
|
||||
|
||||
let lhs = match left.loc {
|
||||
Loc::Reg(reg) => reg,
|
||||
Loc::Imm(imm) => {
|
||||
let reg = self.gpa.allocate();
|
||||
self.code.li64(reg, imm);
|
||||
reg
|
||||
}
|
||||
};
|
||||
|
||||
let rhs = match right.loc {
|
||||
Loc::Reg(reg) => reg,
|
||||
Loc::Imm(imm) => {
|
||||
let reg = self.gpa.allocate();
|
||||
self.code.li64(reg, imm);
|
||||
reg
|
||||
}
|
||||
};
|
||||
|
||||
op(&mut self.code, lhs, lhs, rhs);
|
||||
self.gpa.free(rhs);
|
||||
|
||||
Some(Value {
|
||||
ty: left.ty,
|
||||
loc: Loc::Reg(lhs),
|
||||
})
|
||||
}
|
||||
ast => unimplemented!("{:#?}", ast),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,14 +377,6 @@ mod tests {
|
|||
|
||||
let mut stack = [0_u64; 1024];
|
||||
|
||||
for (i, b) in out.iter().enumerate() {
|
||||
write!(output, "{:02x}", b).unwrap();
|
||||
if (i + 1) % 4 == 0 {
|
||||
writeln!(output).unwrap();
|
||||
}
|
||||
}
|
||||
writeln!(output).unwrap();
|
||||
|
||||
let mut vm = unsafe {
|
||||
hbvm::Vm::<TestMem, 0>::new(TestMem, hbvm::mem::Address::new(out.as_ptr() as u64))
|
||||
};
|
||||
|
@ -356,5 +397,6 @@ mod tests {
|
|||
|
||||
crate::run_tests! { generate:
|
||||
example => include_str!("../examples/main_fn.hb");
|
||||
arithmetic => include_str!("../examples/arithmetic.hb");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ impl Token {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum TokenKind {
|
||||
Ident,
|
||||
Number,
|
||||
|
@ -22,6 +22,10 @@ pub enum TokenKind {
|
|||
LBrack,
|
||||
RBrack,
|
||||
Decl,
|
||||
Plus,
|
||||
Minus,
|
||||
Star,
|
||||
FSlash,
|
||||
Or,
|
||||
Semi,
|
||||
Colon,
|
||||
|
@ -30,6 +34,44 @@ pub enum TokenKind {
|
|||
Error,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TokenKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
use TokenKind as T;
|
||||
let s = match self {
|
||||
T::Ident => "<identifier>",
|
||||
T::Number => "<number>",
|
||||
T::LParen => "(",
|
||||
T::RParen => ")",
|
||||
T::LBrace => "{",
|
||||
T::RBrace => "}",
|
||||
T::LBrack => "[",
|
||||
T::RBrack => "]",
|
||||
T::Decl => ":=",
|
||||
T::Plus => "+",
|
||||
T::Minus => "-",
|
||||
T::Star => "*",
|
||||
T::FSlash => "/",
|
||||
T::Or => "||",
|
||||
T::Semi => ";",
|
||||
T::Colon => ":",
|
||||
T::Return => "return",
|
||||
T::Eof => "<eof>",
|
||||
T::Error => "<error>",
|
||||
};
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenKind {
|
||||
pub fn precedence(&self) -> Option<u8> {
|
||||
match self {
|
||||
Self::Plus | Self::Minus => Some(2),
|
||||
Self::Star | Self::FSlash => Some(3),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Lexer<'a> {
|
||||
pos: u32,
|
||||
bytes: &'a [u8],
|
||||
|
@ -120,6 +162,10 @@ impl<'a> Iterator for Lexer<'a> {
|
|||
false => T::Colon,
|
||||
},
|
||||
b';' => T::Semi,
|
||||
b'+' => T::Plus,
|
||||
b'-' => T::Minus,
|
||||
b'*' => T::Star,
|
||||
b'/' => T::FSlash,
|
||||
b'|' => match self.advance_if(b'|') {
|
||||
true => T::Or,
|
||||
false => T::Error,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(noop_waker)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(non_null_convenience)]
|
||||
#![allow(dead_code)]
|
||||
#![feature(const_mut_refs)]
|
||||
|
|
|
@ -45,6 +45,34 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
}
|
||||
|
||||
fn expr(&mut self) -> Expr<'a> {
|
||||
let left = self.unit_expr();
|
||||
self.bin_expr(left, 0)
|
||||
}
|
||||
|
||||
fn bin_expr(&mut self, mut left: Expr<'a>, min_prec: u8) -> Expr<'a> {
|
||||
loop {
|
||||
let Some(prec) = self.token.kind.precedence() else {
|
||||
break;
|
||||
};
|
||||
|
||||
if prec < min_prec {
|
||||
break;
|
||||
}
|
||||
|
||||
let op = self.next().kind;
|
||||
let right = self.unit_expr();
|
||||
let right = self.bin_expr(right, prec);
|
||||
left = Expr::BinOp {
|
||||
left: self.arena.alloc(left),
|
||||
right: self.arena.alloc(right),
|
||||
op,
|
||||
};
|
||||
}
|
||||
|
||||
left
|
||||
}
|
||||
|
||||
fn unit_expr(&mut self) -> Expr<'a> {
|
||||
let token = self.next();
|
||||
let expr = match token.kind {
|
||||
TokenKind::Ident => {
|
||||
|
@ -74,6 +102,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
Err(e) => self.report(format_args!("invalid number: {e}")),
|
||||
},
|
||||
},
|
||||
TokenKind::LParen => {
|
||||
let expr = self.expr();
|
||||
self.expect_advance(TokenKind::RParen);
|
||||
expr
|
||||
}
|
||||
tok => self.report(format_args!("unexpected token: {tok:?}")),
|
||||
};
|
||||
|
||||
|
@ -140,6 +173,11 @@ pub enum Expr<'a> {
|
|||
Number {
|
||||
value: u64,
|
||||
},
|
||||
BinOp {
|
||||
left: Ptr<'a, Expr<'a>>,
|
||||
op: TokenKind,
|
||||
right: Ptr<'a, Expr<'a>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> std::fmt::Display for Expr<'a> {
|
||||
|
@ -148,7 +186,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
|||
static INDENT: Cell<usize> = Cell::new(0);
|
||||
}
|
||||
|
||||
match self {
|
||||
match *self {
|
||||
Self::Decl { name, val } => write!(f, "{} := {}", name, val),
|
||||
Self::Closure { ret, body } => write!(f, "||: {} {}", ret, body),
|
||||
Self::Return { val: Some(val) } => write!(f, "return {};", val),
|
||||
|
@ -158,7 +196,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
|||
writeln!(f, "{{")?;
|
||||
INDENT.with(|i| i.set(i.get() + 1));
|
||||
let res = crate::try_block(|| {
|
||||
for stmt in *stmts {
|
||||
for stmt in stmts {
|
||||
for _ in 0..INDENT.with(|i| i.get()) {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
|
@ -171,6 +209,21 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
|||
res
|
||||
}
|
||||
Self::Number { value } => write!(f, "{}", value),
|
||||
Self::BinOp { left, right, op } => {
|
||||
let display_branch = |f: &mut std::fmt::Formatter, expr: &Self| {
|
||||
if let Self::BinOp { op: lop, .. } = expr
|
||||
&& op.precedence() > lop.precedence()
|
||||
{
|
||||
write!(f, "({})", expr)
|
||||
} else {
|
||||
write!(f, "{}", expr)
|
||||
}
|
||||
};
|
||||
|
||||
display_branch(f, left)?;
|
||||
write!(f, " {} ", op)?;
|
||||
display_branch(f, right)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -360,5 +413,6 @@ mod tests {
|
|||
|
||||
crate::run_tests! { parse:
|
||||
example => include_str!("../examples/main_fn.hb");
|
||||
arithmetic => include_str!("../examples/arithmetic.hb");
|
||||
}
|
||||
}
|
||||
|
|
2
hblang/tests/hblang::codegen::tests::arithmetic.txt
Normal file
2
hblang/tests/hblang::codegen::tests::arithmetic.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
ret: 1
|
||||
status: Ok(())
|
|
@ -1,10 +1,2 @@
|
|||
541f0005
|
||||
00000001
|
||||
4b010100
|
||||
00000000
|
||||
00005500
|
||||
1f000000
|
||||
00000000
|
||||
00
|
||||
ret: 1
|
||||
status: Ok(())
|
||||
|
|
29
hblang/tests/hblang::lexer::tests::arithmetic.txt
Normal file
29
hblang/tests/hblang::lexer::tests::arithmetic.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
Ident "main"
|
||||
Decl ":="
|
||||
Or "||"
|
||||
Colon ":"
|
||||
Ident "int"
|
||||
LBrace "{"
|
||||
Return "return"
|
||||
Number "10"
|
||||
Minus "-"
|
||||
Number "20"
|
||||
FSlash "/"
|
||||
Number "2"
|
||||
Plus "+"
|
||||
Number "4"
|
||||
Star "*"
|
||||
LParen "("
|
||||
Number "2"
|
||||
Plus "+"
|
||||
Number "2"
|
||||
RParen ")"
|
||||
Minus "-"
|
||||
Number "4"
|
||||
Star "*"
|
||||
Number "4"
|
||||
Plus "+"
|
||||
Number "1"
|
||||
Semi ";"
|
||||
RBrace "}"
|
||||
Eof ""
|
3
hblang/tests/hblang::parser::tests::arithmetic.txt
Normal file
3
hblang/tests/hblang::parser::tests::arithmetic.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
main := ||: int {
|
||||
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1;
|
||||
}
|
Loading…
Reference in a new issue