adding directives
This commit is contained in:
parent
d8a922df26
commit
70955c1792
9
hblang/examples/directives.hb
Normal file
9
hblang/examples/directives.hb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
Type := struct {
|
||||||
|
brah: int,
|
||||||
|
blah: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
main := fn(): int {
|
||||||
|
return @eca(int, 1, Type.(10, 20), @sizeof(Type), @alignof(Type), 5, 6);
|
||||||
|
}
|
|
@ -129,6 +129,7 @@ enum Ctx {
|
||||||
None,
|
None,
|
||||||
Inferred(Type),
|
Inferred(Type),
|
||||||
Dest(Value),
|
Dest(Value),
|
||||||
|
DestUntyped(Loc, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctx {
|
impl Ctx {
|
||||||
|
@ -139,6 +140,14 @@ impl Ctx {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn loc(self) -> Option<Loc> {
|
||||||
|
Some(match self {
|
||||||
|
Self::Dest(Value { loc, .. }) => loc,
|
||||||
|
Self::DestUntyped(loc, ..) => loc,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod bt {
|
pub mod bt {
|
||||||
|
@ -734,8 +743,129 @@ impl<'a> Codegen<'a> {
|
||||||
self.expr_ctx(expr, Ctx::default())
|
self.expr_ctx(expr, Ctx::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_ctx(&mut self, expr: &'a parser::Expr<'a>, ctx: Ctx) -> Option<Value> {
|
fn expr_ctx(&mut self, expr: &'a parser::Expr<'a>, mut ctx: Ctx) -> Option<Value> {
|
||||||
let value = match *expr {
|
let value = match *expr {
|
||||||
|
E::Directive {
|
||||||
|
name: "eca",
|
||||||
|
args: [ret_ty, args @ ..],
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let mut parama = 3..12;
|
||||||
|
let mut values = Vec::with_capacity(args.len());
|
||||||
|
for arg in args {
|
||||||
|
let arg = self.expr(arg)?;
|
||||||
|
self.pass_arg(&arg, &mut parama);
|
||||||
|
values.push(arg.loc);
|
||||||
|
}
|
||||||
|
drop(values);
|
||||||
|
|
||||||
|
let ty = self.ty(ret_ty);
|
||||||
|
let loc = self.alloc_ret_loc(ty, ctx);
|
||||||
|
|
||||||
|
self.code.encode(instrs::eca());
|
||||||
|
|
||||||
|
self.post_process_ret_loc(ty, &loc);
|
||||||
|
|
||||||
|
return Some(Value { ty, loc });
|
||||||
|
}
|
||||||
|
E::Directive {
|
||||||
|
name: "sizeof",
|
||||||
|
args: [ty],
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let ty = self.ty(ty);
|
||||||
|
let loc = Loc::Imm(self.size_of(ty));
|
||||||
|
return Some(Value { ty: bt::UINT, loc });
|
||||||
|
}
|
||||||
|
E::Directive {
|
||||||
|
name: "alignof",
|
||||||
|
args: [ty],
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let ty = self.ty(ty);
|
||||||
|
let loc = Loc::Imm(self.align_of(ty));
|
||||||
|
return Some(Value { ty: bt::UINT, loc });
|
||||||
|
}
|
||||||
|
E::Directive {
|
||||||
|
name: "intcast",
|
||||||
|
args: [val],
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let Some(ty) = ctx.ty() else {
|
||||||
|
self.report(
|
||||||
|
expr.pos(),
|
||||||
|
"type to cast to is unknown, use `@as(<type>, <expr>)`",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
let mut val = self.expr(val)?;
|
||||||
|
|
||||||
|
let from_size = self.size_of(val.ty);
|
||||||
|
let to_size = self.size_of(ty);
|
||||||
|
|
||||||
|
if from_size < to_size && bt::is_signed(val.ty) {
|
||||||
|
let reg = self.loc_to_reg(val.loc, from_size);
|
||||||
|
let op =
|
||||||
|
[instrs::sxt8, instrs::sxt16, instrs::sxt32][from_size.ilog2() as usize];
|
||||||
|
self.code.encode(op(reg.0, reg.0));
|
||||||
|
val.loc = Loc::Reg(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Value { ty, loc: val.loc })
|
||||||
|
}
|
||||||
|
E::Directive {
|
||||||
|
name: "bitcast",
|
||||||
|
args: [val],
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let Some(ty) = ctx.ty() else {
|
||||||
|
self.report(
|
||||||
|
expr.pos(),
|
||||||
|
"type to cast to is unknown, use `@as(<type>, <expr>)`",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let size = self.size_of(ty);
|
||||||
|
|
||||||
|
ctx = match ctx {
|
||||||
|
Ctx::Dest(Value { loc, .. }) | Ctx::DestUntyped(loc, ..) => {
|
||||||
|
Ctx::DestUntyped(loc, size as _)
|
||||||
|
}
|
||||||
|
_ => Ctx::None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let val = self.expr_ctx(val, ctx)?;
|
||||||
|
|
||||||
|
if self.size_of(val.ty) != size {
|
||||||
|
self.report(
|
||||||
|
expr.pos(),
|
||||||
|
format_args!(
|
||||||
|
"cannot bitcast {} to {} (different sizes: {} != {size})",
|
||||||
|
self.display_ty(val.ty),
|
||||||
|
self.display_ty(ty),
|
||||||
|
self.size_of(val.ty),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: maybe check align
|
||||||
|
|
||||||
|
return Some(Value { ty, loc: val.loc });
|
||||||
|
}
|
||||||
|
E::Directive {
|
||||||
|
name: "as",
|
||||||
|
args: [ty, val],
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let ty = self.ty(ty);
|
||||||
|
let ctx = match ctx {
|
||||||
|
Ctx::Dest(dest) => Ctx::Dest(dest),
|
||||||
|
Ctx::DestUntyped(loc, size) if self.size_of(ty) == size => {
|
||||||
|
Ctx::Dest(Value { ty, loc })
|
||||||
|
}
|
||||||
|
_ => Ctx::Inferred(ty),
|
||||||
|
};
|
||||||
|
return self.expr_ctx(val, ctx);
|
||||||
|
}
|
||||||
E::Bool { value, .. } => Some(Value {
|
E::Bool { value, .. } => Some(Value {
|
||||||
ty: bt::BOOL,
|
ty: bt::BOOL,
|
||||||
loc: Loc::Imm(value as u64),
|
loc: Loc::Imm(value as u64),
|
||||||
|
@ -748,8 +878,8 @@ impl<'a> Codegen<'a> {
|
||||||
};
|
};
|
||||||
let size = self.size_of(ty);
|
let size = self.size_of(ty);
|
||||||
|
|
||||||
let loc = match ctx {
|
let loc = match ctx.loc() {
|
||||||
Ctx::Dest(dest) => dest.loc,
|
Some(loc) => loc,
|
||||||
_ => Loc::Stack(self.alloc_stack(size), 0),
|
_ => Loc::Stack(self.alloc_stack(size), 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -878,40 +1008,11 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
drop(values);
|
drop(values);
|
||||||
|
|
||||||
let size = self.size_of(fn_label.ret);
|
let loc = self.alloc_ret_loc(fn_label.ret, ctx);
|
||||||
let loc = match size {
|
|
||||||
0 => Loc::Imm(0),
|
|
||||||
..=8 => Loc::RegRef(1),
|
|
||||||
..=16 => match ctx {
|
|
||||||
Ctx::Dest(dest) => dest.loc,
|
|
||||||
_ => Loc::Stack(self.alloc_stack(size), 0),
|
|
||||||
},
|
|
||||||
..=u64::MAX => {
|
|
||||||
let val = match ctx {
|
|
||||||
Ctx::Dest(dest) => dest.loc,
|
|
||||||
_ => Loc::Stack(self.alloc_stack(size), 0),
|
|
||||||
};
|
|
||||||
let (ptr, off) = val.ref_to_ptr();
|
|
||||||
self.code.encode(instrs::cp(1, ptr));
|
|
||||||
self.code.addi64(1, ptr, off);
|
|
||||||
val
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.code.call(func);
|
self.code.call(func);
|
||||||
|
|
||||||
match size {
|
self.post_process_ret_loc(fn_label.ret, &loc);
|
||||||
0 => {}
|
|
||||||
..=8 => {}
|
|
||||||
..=16 => {
|
|
||||||
if let Loc::Stack(ref stack, off) = loc {
|
|
||||||
self.store_stack(1, stack.offset + off, 16);
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
..=u64::MAX => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(Value {
|
return Some(Value {
|
||||||
ty: fn_label.ret,
|
ty: fn_label.ret,
|
||||||
|
@ -1156,11 +1257,18 @@ impl<'a> Codegen<'a> {
|
||||||
ast => unimplemented!("{:#?}", ast),
|
ast => unimplemented!("{:#?}", ast),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
if let Ctx::Dest(dest) = ctx {
|
match ctx {
|
||||||
self.assign(dest.ty, dest.loc, value.loc);
|
Ctx::Dest(dest) => {
|
||||||
|
_ = self.assert_ty(expr.pos(), dest.ty, value.ty);
|
||||||
|
self.assign(dest.ty, dest.loc, value.loc)?;
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
} else {
|
}
|
||||||
Some(value)
|
Ctx::DestUntyped(loc, size) => {
|
||||||
|
// Wo dont check since bitcast does
|
||||||
|
self.assign_opaque(size, loc, value.loc);
|
||||||
|
Some(Value::VOID)
|
||||||
|
}
|
||||||
|
_ => Some(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1269,13 +1377,11 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign(&mut self, ty: Type, right: Loc, left: Loc) -> Option<Value> {
|
fn assign_opaque(&mut self, size: u64, right: Loc, left: Loc) -> Option<Value> {
|
||||||
if left == right {
|
if left == right {
|
||||||
return Some(Value::VOID);
|
return Some(Value::VOID);
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = self.size_of(ty);
|
|
||||||
|
|
||||||
match size {
|
match size {
|
||||||
0 => {}
|
0 => {}
|
||||||
..=8 => {
|
..=8 => {
|
||||||
|
@ -1309,6 +1415,10 @@ impl<'a> Codegen<'a> {
|
||||||
Some(Value::VOID)
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assign(&mut self, ty: Type, right: Loc, left: Loc) -> Option<Value> {
|
||||||
|
self.assign_opaque(self.size_of(ty), right, left)
|
||||||
|
}
|
||||||
|
|
||||||
fn to_ptr(&mut self, loc: Loc) -> LinReg {
|
fn to_ptr(&mut self, loc: Loc) -> LinReg {
|
||||||
match loc {
|
match loc {
|
||||||
Loc::Deref(reg, .., off) => {
|
Loc::Deref(reg, .., off) => {
|
||||||
|
@ -1521,6 +1631,44 @@ impl<'a> Codegen<'a> {
|
||||||
println!("{}:{}:{}: {}", self.path, line, col, msg);
|
println!("{}:{}:{}: {}", self.path, line, col, msg);
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn alloc_ret_loc(&mut self, ret: Type, ctx: Ctx) -> Loc {
|
||||||
|
let size = self.size_of(ret);
|
||||||
|
match size {
|
||||||
|
0 => Loc::Imm(0),
|
||||||
|
..=8 => Loc::RegRef(1),
|
||||||
|
..=16 => match ctx {
|
||||||
|
Ctx::Dest(dest) => dest.loc,
|
||||||
|
_ => Loc::Stack(self.alloc_stack(size), 0),
|
||||||
|
},
|
||||||
|
..=u64::MAX => {
|
||||||
|
let val = match ctx {
|
||||||
|
Ctx::Dest(dest) => dest.loc,
|
||||||
|
_ => Loc::Stack(self.alloc_stack(size), 0),
|
||||||
|
};
|
||||||
|
let (ptr, off) = val.ref_to_ptr();
|
||||||
|
self.code.encode(instrs::cp(1, ptr));
|
||||||
|
self.code.addi64(1, ptr, off);
|
||||||
|
val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_process_ret_loc(&mut self, ty: Type, loc: &Loc) {
|
||||||
|
let size = self.size_of(ty);
|
||||||
|
match size {
|
||||||
|
0 => {}
|
||||||
|
..=8 => {}
|
||||||
|
..=16 => {
|
||||||
|
if let Loc::Stack(ref stack, off) = loc {
|
||||||
|
self.store_stack(1, stack.offset + off, size as _);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
..=u64::MAX => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1704,5 +1852,6 @@ mod tests {
|
||||||
structs => include_str!("../examples/structs.hb");
|
structs => include_str!("../examples/structs.hb");
|
||||||
different_types => include_str!("../examples/different_types.hb");
|
different_types => include_str!("../examples/different_types.hb");
|
||||||
struct_operators => include_str!("../examples/struct_operators.hb");
|
struct_operators => include_str!("../examples/struct_operators.hb");
|
||||||
|
directives => include_str!("../examples/directives.hb");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,7 @@ gen_token_kind! {
|
||||||
Number,
|
Number,
|
||||||
Eof,
|
Eof,
|
||||||
Error,
|
Error,
|
||||||
|
Driective,
|
||||||
#[keywords]
|
#[keywords]
|
||||||
Return = b"return",
|
Return = b"return",
|
||||||
If = b"if",
|
If = b"if",
|
||||||
|
@ -195,7 +196,7 @@ impl<'a> Iterator for Lexer<'a> {
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
use TokenKind as T;
|
use TokenKind as T;
|
||||||
loop {
|
loop {
|
||||||
let start = self.pos;
|
let mut start = self.pos;
|
||||||
let kind = match self.advance()? {
|
let kind = match self.advance()? {
|
||||||
b'\n' | b'\r' | b'\t' | b' ' => continue,
|
b'\n' | b'\r' | b'\t' | b' ' => continue,
|
||||||
b'0'..=b'9' => {
|
b'0'..=b'9' => {
|
||||||
|
@ -204,14 +205,19 @@ impl<'a> Iterator for Lexer<'a> {
|
||||||
}
|
}
|
||||||
T::Number
|
T::Number
|
||||||
}
|
}
|
||||||
b'a'..=b'z' | b'A'..=b'Z' | b'_' => {
|
c @ (b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'@') => {
|
||||||
while let Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') = self.peek() {
|
while let Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') = self.peek() {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c == b'@' {
|
||||||
|
start += 1;
|
||||||
|
T::Driective
|
||||||
|
} else {
|
||||||
let ident = &self.bytes[start as usize..self.pos as usize];
|
let ident = &self.bytes[start as usize..self.pos as usize];
|
||||||
T::from_ident(ident)
|
T::from_ident(ident)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
b':' if self.advance_if(b'=') => T::Decl,
|
b':' if self.advance_if(b'=') => T::Decl,
|
||||||
b':' => T::Colon,
|
b':' => T::Colon,
|
||||||
b',' => T::Comma,
|
b',' => T::Comma,
|
||||||
|
|
|
@ -153,6 +153,14 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
let frame = self.idents.len();
|
let frame = self.idents.len();
|
||||||
let token = self.next();
|
let token = self.next();
|
||||||
let mut expr = match token.kind {
|
let mut expr = match token.kind {
|
||||||
|
T::Driective => E::Directive {
|
||||||
|
pos: token.start,
|
||||||
|
name: self.lexer.slice(token.range()),
|
||||||
|
args: {
|
||||||
|
self.expect_advance(T::LParen);
|
||||||
|
self.collect_list(T::Comma, T::RParen, Self::expr)
|
||||||
|
},
|
||||||
|
},
|
||||||
T::True => E::Bool {
|
T::True => E::Bool {
|
||||||
pos: token.start,
|
pos: token.start,
|
||||||
value: true,
|
value: true,
|
||||||
|
@ -428,6 +436,11 @@ pub enum Expr<'a> {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
value: bool,
|
value: bool,
|
||||||
},
|
},
|
||||||
|
Directive {
|
||||||
|
pos: u32,
|
||||||
|
name: &'a str,
|
||||||
|
args: &'a [Self],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Expr<'a> {
|
impl<'a> Expr<'a> {
|
||||||
|
@ -436,6 +449,7 @@ impl<'a> Expr<'a> {
|
||||||
Self::Call { func, .. } => func.pos(),
|
Self::Call { func, .. } => func.pos(),
|
||||||
Self::Ident { id, .. } => ident::pos(*id),
|
Self::Ident { id, .. } => ident::pos(*id),
|
||||||
Self::Break { pos }
|
Self::Break { pos }
|
||||||
|
| Self::Directive { pos, .. }
|
||||||
| Self::Continue { pos }
|
| Self::Continue { pos }
|
||||||
| Self::Closure { pos, .. }
|
| Self::Closure { pos, .. }
|
||||||
| Self::Block { pos, .. }
|
| Self::Block { pos, .. }
|
||||||
|
@ -459,18 +473,31 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
static INDENT: Cell<usize> = Cell::new(0);
|
static INDENT: Cell<usize> = Cell::new(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
match *self {
|
fn fmt_list<'a, T>(
|
||||||
Self::Field { target, field } => write!(f, "{}.{}", target, field),
|
f: &mut std::fmt::Formatter,
|
||||||
Self::Struct { fields, .. } => {
|
end: &str,
|
||||||
write!(f, "struct {{")?;
|
list: &'a [T],
|
||||||
|
fmt: impl Fn(&T, &mut std::fmt::Formatter) -> std::fmt::Result,
|
||||||
|
) -> std::fmt::Result {
|
||||||
let first = &mut true;
|
let first = &mut true;
|
||||||
for (name, ty) in fields {
|
for expr in list {
|
||||||
if !std::mem::take(first) {
|
if !std::mem::take(first) {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
write!(f, "{}: {}", name, ty)?;
|
fmt(expr, f)?;
|
||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "{end}")
|
||||||
|
}
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
Self::Field { target, field } => write!(f, "{target}.{field}"),
|
||||||
|
Self::Directive { name, args, .. } => {
|
||||||
|
write!(f, "@{name}(")?;
|
||||||
|
fmt_list(f, ")", args, std::fmt::Display::fmt)
|
||||||
|
}
|
||||||
|
Self::Struct { fields, .. } => {
|
||||||
|
write!(f, "struct {{")?;
|
||||||
|
fmt_list(f, "}", fields, |(name, val), f| write!(f, "{name}: {val}",))
|
||||||
}
|
}
|
||||||
Self::Ctor { ty, fields, .. } => {
|
Self::Ctor { ty, fields, .. } => {
|
||||||
let (left, rith) = if fields.iter().any(|(name, _)| name.is_some()) {
|
let (left, rith) = if fields.iter().any(|(name, _)| name.is_some()) {
|
||||||
|
@ -482,7 +509,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
if let Some(ty) = ty {
|
if let Some(ty) = ty {
|
||||||
write!(f, "{ty}")?;
|
write!(f, "{ty}")?;
|
||||||
}
|
}
|
||||||
write!(f, ".{}", left)?;
|
write!(f, ".{left}")?;
|
||||||
let first = &mut true;
|
let first = &mut true;
|
||||||
for (name, val) in fields {
|
for (name, val) in fields {
|
||||||
if !std::mem::take(first) {
|
if !std::mem::take(first) {
|
||||||
|
@ -495,46 +522,33 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
}
|
}
|
||||||
write!(f, "{rith}")
|
write!(f, "{rith}")
|
||||||
}
|
}
|
||||||
Self::UnOp { op, val, .. } => write!(f, "{}{}", op, val),
|
Self::UnOp { op, val, .. } => write!(f, "{op}{val}"),
|
||||||
Self::Break { .. } => write!(f, "break;"),
|
Self::Break { .. } => write!(f, "break;"),
|
||||||
Self::Continue { .. } => write!(f, "continue;"),
|
Self::Continue { .. } => write!(f, "continue;"),
|
||||||
Self::If {
|
Self::If {
|
||||||
cond, then, else_, ..
|
cond, then, else_, ..
|
||||||
} => {
|
} => {
|
||||||
write!(f, "if {} {}", cond, then)?;
|
write!(f, "if {cond} {then}")?;
|
||||||
if let Some(else_) = else_ {
|
if let Some(else_) = else_ {
|
||||||
write!(f, " else {}", else_)?;
|
write!(f, " else {else_}")?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Self::Loop { body, .. } => write!(f, "loop {}", body),
|
Self::Loop { body, .. } => write!(f, "loop {body}"),
|
||||||
Self::Closure {
|
Self::Closure {
|
||||||
ret, body, args, ..
|
ret, body, args, ..
|
||||||
} => {
|
} => {
|
||||||
write!(f, "|")?;
|
write!(f, "fn(")?;
|
||||||
let first = &mut true;
|
fmt_list(f, "", args, |arg, f| write!(f, "{}: {}", arg.name, arg.ty))?;
|
||||||
for arg in args {
|
write!(f, "): {ret} {body}")
|
||||||
if !std::mem::take(first) {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
|
||||||
write!(f, "{}: {}", arg.name, arg.ty)?;
|
|
||||||
}
|
|
||||||
write!(f, "|: {} {}", ret, body)
|
|
||||||
}
|
}
|
||||||
Self::Call { func, args } => {
|
Self::Call { func, args } => {
|
||||||
write!(f, "{}(", func)?;
|
write!(f, "{func}(")?;
|
||||||
let first = &mut true;
|
fmt_list(f, ")", args, std::fmt::Display::fmt)
|
||||||
for arg in args {
|
|
||||||
if !std::mem::take(first) {
|
|
||||||
write!(f, ", ")?;
|
|
||||||
}
|
}
|
||||||
write!(f, "{}", arg)?;
|
Self::Return { val: Some(val), .. } => write!(f, "return {val};"),
|
||||||
}
|
|
||||||
write!(f, ")")
|
|
||||||
}
|
|
||||||
Self::Return { val: Some(val), .. } => write!(f, "return {};", val),
|
|
||||||
Self::Return { val: None, .. } => write!(f, "return;"),
|
Self::Return { val: None, .. } => write!(f, "return;"),
|
||||||
Self::Ident { name, .. } => write!(f, "{}", name),
|
Self::Ident { name, .. } => write!(f, "{name}"),
|
||||||
Self::Block { stmts, .. } => {
|
Self::Block { stmts, .. } => {
|
||||||
writeln!(f, "{{")?;
|
writeln!(f, "{{")?;
|
||||||
INDENT.with(|i| i.set(i.get() + 1));
|
INDENT.with(|i| i.set(i.get() + 1));
|
||||||
|
@ -543,7 +557,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
for _ in 0..INDENT.with(|i| i.get()) {
|
for _ in 0..INDENT.with(|i| i.get()) {
|
||||||
write!(f, " ")?;
|
write!(f, " ")?;
|
||||||
}
|
}
|
||||||
writeln!(f, "{}", stmt)?;
|
writeln!(f, "{stmt}")?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})();
|
})();
|
||||||
|
@ -551,21 +565,21 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
write!(f, "}}")?;
|
write!(f, "}}")?;
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
Self::Number { value, .. } => write!(f, "{}", value),
|
Self::Number { value, .. } => write!(f, "{value}"),
|
||||||
Self::Bool { value, .. } => write!(f, "{}", value),
|
Self::Bool { value, .. } => write!(f, "{value}"),
|
||||||
Self::BinOp { left, right, op } => {
|
Self::BinOp { left, right, op } => {
|
||||||
let display_branch = |f: &mut std::fmt::Formatter, expr: &Self| {
|
let display_branch = |f: &mut std::fmt::Formatter, expr: &Self| {
|
||||||
if let Self::BinOp { op: lop, .. } = expr
|
if let Self::BinOp { op: lop, .. } = expr
|
||||||
&& op.precedence() > lop.precedence()
|
&& op.precedence() > lop.precedence()
|
||||||
{
|
{
|
||||||
write!(f, "({})", expr)
|
write!(f, "({expr})")
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", expr)
|
write!(f, "{expr}")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
display_branch(f, left)?;
|
display_branch(f, left)?;
|
||||||
write!(f, " {} ", op)?;
|
write!(f, " {op} ")?;
|
||||||
display_branch(f, right)
|
display_branch(f, right)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
hblang/tests/codegen_tests_directives.txt
Normal file
4
hblang/tests/codegen_tests_directives.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
ev: Ecall
|
||||||
|
code size: 217
|
||||||
|
ret: 0
|
||||||
|
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
||||||
main := ||: int {
|
main := fn(): int {
|
||||||
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1;
|
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
main := ||: int {
|
main := fn(): int {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue