adding directives

This commit is contained in:
mlokr 2024-05-14 23:07:32 +02:00
parent d8a922df26
commit 70955c1792
7 changed files with 270 additions and 88 deletions

View 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);
}

View file

@ -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) => {
Some(Value::VOID) _ = self.assert_ty(expr.pos(), dest.ty, value.ty);
} else { self.assign(dest.ty, dest.loc, value.loc)?;
Some(value) Some(Value::VOID)
}
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");
} }
} }

View file

@ -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,13 +205,18 @@ 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();
} }
let ident = &self.bytes[start as usize..self.pos as usize]; if c == b'@' {
T::from_ident(ident) start += 1;
T::Driective
} else {
let ident = &self.bytes[start as usize..self.pos as usize];
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,

View file

@ -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);
} }
fn fmt_list<'a, T>(
f: &mut std::fmt::Formatter,
end: &str,
list: &'a [T],
fmt: impl Fn(&T, &mut std::fmt::Formatter) -> std::fmt::Result,
) -> std::fmt::Result {
let first = &mut true;
for expr in list {
if !std::mem::take(first) {
write!(f, ", ")?;
}
fmt(expr, f)?;
}
write!(f, "{end}")
}
match *self { match *self {
Self::Field { target, field } => write!(f, "{}.{}", target, field), 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, .. } => { Self::Struct { fields, .. } => {
write!(f, "struct {{")?; write!(f, "struct {{")?;
let first = &mut true; fmt_list(f, "}", fields, |(name, val), f| write!(f, "{name}: {val}",))
for (name, ty) in fields {
if !std::mem::take(first) {
write!(f, ", ")?;
}
write!(f, "{}: {}", name, ty)?;
}
write!(f, "}}")
} }
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)?;
}
write!(f, ")")
} }
Self::Return { val: Some(val), .. } => write!(f, "return {};", val), 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)
} }
} }

View file

@ -0,0 +1,4 @@
ev: Ecall
code size: 217
ret: 0
status: Ok(())

View file

@ -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;
} }

View file

@ -1,3 +1,3 @@
main := ||: int { main := fn(): int {
return 1; return 1;
} }