now compiling some trivial arithmetic
This commit is contained in:
parent
81952cfc40
commit
cf99091a45
|
@ -1,3 +1,3 @@
|
||||||
main := ||: int {
|
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 {
|
use {
|
||||||
crate::parser::{self, Expr},
|
crate::{
|
||||||
|
lexer,
|
||||||
|
parser::{self, Expr},
|
||||||
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,6 +69,10 @@ impl Func {
|
||||||
self.tx();
|
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) {
|
fn relocate(&mut self, labels: &[Label], shift: i64) {
|
||||||
for reloc in self.relocs.drain(..) {
|
for reloc in self.relocs.drain(..) {
|
||||||
let label = &labels[reloc.id as usize];
|
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>> {
|
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 {
|
match *expr {
|
||||||
E::Decl {
|
E::Decl {
|
||||||
name,
|
name,
|
||||||
val: E::Closure { ret, body },
|
val: E::Closure { ret, body },
|
||||||
} => {
|
} => {
|
||||||
let frame = self.add_label(name);
|
let frame = self.add_label(name);
|
||||||
|
self.gpa.init_caller();
|
||||||
self.ret = **ret;
|
self.ret = **ret;
|
||||||
self.expr(body, None);
|
self.expr(body, None);
|
||||||
self.write_fn_prelude(frame);
|
self.write_fn_prelude(frame);
|
||||||
|
@ -194,7 +202,48 @@ 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),
|
||||||
}),
|
}),
|
||||||
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];
|
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 {
|
let mut vm = unsafe {
|
||||||
hbvm::Vm::<TestMem, 0>::new(TestMem, hbvm::mem::Address::new(out.as_ptr() as u64))
|
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:
|
crate::run_tests! { generate:
|
||||||
example => include_str!("../examples/main_fn.hb");
|
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 {
|
pub enum TokenKind {
|
||||||
Ident,
|
Ident,
|
||||||
Number,
|
Number,
|
||||||
|
@ -22,6 +22,10 @@ pub enum TokenKind {
|
||||||
LBrack,
|
LBrack,
|
||||||
RBrack,
|
RBrack,
|
||||||
Decl,
|
Decl,
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
Star,
|
||||||
|
FSlash,
|
||||||
Or,
|
Or,
|
||||||
Semi,
|
Semi,
|
||||||
Colon,
|
Colon,
|
||||||
|
@ -30,6 +34,44 @@ pub enum TokenKind {
|
||||||
Error,
|
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> {
|
pub struct Lexer<'a> {
|
||||||
pos: u32,
|
pos: u32,
|
||||||
bytes: &'a [u8],
|
bytes: &'a [u8],
|
||||||
|
@ -120,6 +162,10 @@ impl<'a> Iterator for Lexer<'a> {
|
||||||
false => T::Colon,
|
false => T::Colon,
|
||||||
},
|
},
|
||||||
b';' => T::Semi,
|
b';' => T::Semi,
|
||||||
|
b'+' => T::Plus,
|
||||||
|
b'-' => T::Minus,
|
||||||
|
b'*' => T::Star,
|
||||||
|
b'/' => T::FSlash,
|
||||||
b'|' => match self.advance_if(b'|') {
|
b'|' => match self.advance_if(b'|') {
|
||||||
true => T::Or,
|
true => T::Or,
|
||||||
false => T::Error,
|
false => T::Error,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#![feature(noop_waker)]
|
#![feature(noop_waker)]
|
||||||
|
#![feature(let_chains)]
|
||||||
#![feature(non_null_convenience)]
|
#![feature(non_null_convenience)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![feature(const_mut_refs)]
|
#![feature(const_mut_refs)]
|
||||||
|
|
|
@ -45,6 +45,34 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr(&mut self) -> Expr<'a> {
|
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 token = self.next();
|
||||||
let expr = match token.kind {
|
let expr = match token.kind {
|
||||||
TokenKind::Ident => {
|
TokenKind::Ident => {
|
||||||
|
@ -74,6 +102,11 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
Err(e) => self.report(format_args!("invalid number: {e}")),
|
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:?}")),
|
tok => self.report(format_args!("unexpected token: {tok:?}")),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,6 +173,11 @@ pub enum Expr<'a> {
|
||||||
Number {
|
Number {
|
||||||
value: u64,
|
value: u64,
|
||||||
},
|
},
|
||||||
|
BinOp {
|
||||||
|
left: Ptr<'a, Expr<'a>>,
|
||||||
|
op: TokenKind,
|
||||||
|
right: Ptr<'a, Expr<'a>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> std::fmt::Display for 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);
|
static INDENT: Cell<usize> = Cell::new(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match *self {
|
||||||
Self::Decl { name, val } => write!(f, "{} := {}", name, val),
|
Self::Decl { name, val } => write!(f, "{} := {}", name, val),
|
||||||
Self::Closure { ret, body } => write!(f, "||: {} {}", ret, body),
|
Self::Closure { ret, body } => write!(f, "||: {} {}", ret, body),
|
||||||
Self::Return { val: Some(val) } => write!(f, "return {};", val),
|
Self::Return { val: Some(val) } => write!(f, "return {};", val),
|
||||||
|
@ -158,7 +196,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
writeln!(f, "{{")?;
|
writeln!(f, "{{")?;
|
||||||
INDENT.with(|i| i.set(i.get() + 1));
|
INDENT.with(|i| i.set(i.get() + 1));
|
||||||
let res = crate::try_block(|| {
|
let res = crate::try_block(|| {
|
||||||
for stmt in *stmts {
|
for stmt in stmts {
|
||||||
for _ in 0..INDENT.with(|i| i.get()) {
|
for _ in 0..INDENT.with(|i| i.get()) {
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
}
|
}
|
||||||
|
@ -171,6 +209,21 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
Self::Number { value } => write!(f, "{}", value),
|
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:
|
crate::run_tests! { parse:
|
||||||
example => include_str!("../examples/main_fn.hb");
|
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
|
ret: 1
|
||||||
status: Ok(())
|
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