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,
Inferred(Type),
Dest(Value),
DestUntyped(Loc, u64),
}
impl Ctx {
@ -139,6 +140,14 @@ impl Ctx {
_ => return None,
})
}
fn loc(self) -> Option<Loc> {
Some(match self {
Self::Dest(Value { loc, .. }) => loc,
Self::DestUntyped(loc, ..) => loc,
_ => return None,
})
}
}
pub mod bt {
@ -734,8 +743,129 @@ impl<'a> Codegen<'a> {
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 {
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 {
ty: bt::BOOL,
loc: Loc::Imm(value as u64),
@ -748,8 +878,8 @@ impl<'a> Codegen<'a> {
};
let size = self.size_of(ty);
let loc = match ctx {
Ctx::Dest(dest) => dest.loc,
let loc = match ctx.loc() {
Some(loc) => loc,
_ => Loc::Stack(self.alloc_stack(size), 0),
};
@ -878,40 +1008,11 @@ impl<'a> Codegen<'a> {
}
drop(values);
let size = self.size_of(fn_label.ret);
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
}
};
let loc = self.alloc_ret_loc(fn_label.ret, ctx);
self.code.call(func);
match size {
0 => {}
..=8 => {}
..=16 => {
if let Loc::Stack(ref stack, off) = loc {
self.store_stack(1, stack.offset + off, 16);
} else {
unreachable!()
}
}
..=u64::MAX => {}
}
self.post_process_ret_loc(fn_label.ret, &loc);
return Some(Value {
ty: fn_label.ret,
@ -1156,11 +1257,18 @@ impl<'a> Codegen<'a> {
ast => unimplemented!("{:#?}", ast),
}?;
if let Ctx::Dest(dest) = ctx {
self.assign(dest.ty, dest.loc, value.loc);
Some(Value::VOID)
} else {
Some(value)
match ctx {
Ctx::Dest(dest) => {
_ = self.assert_ty(expr.pos(), dest.ty, value.ty);
self.assign(dest.ty, dest.loc, value.loc)?;
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 {
return Some(Value::VOID);
}
let size = self.size_of(ty);
match size {
0 => {}
..=8 => {
@ -1309,6 +1415,10 @@ impl<'a> Codegen<'a> {
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 {
match loc {
Loc::Deref(reg, .., off) => {
@ -1521,6 +1631,44 @@ impl<'a> Codegen<'a> {
println!("{}:{}:{}: {}", self.path, line, col, msg);
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)]
@ -1704,5 +1852,6 @@ mod tests {
structs => include_str!("../examples/structs.hb");
different_types => include_str!("../examples/different_types.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,
Eof,
Error,
Driective,
#[keywords]
Return = b"return",
If = b"if",
@ -195,7 +196,7 @@ impl<'a> Iterator for Lexer<'a> {
fn next(&mut self) -> Option<Self::Item> {
use TokenKind as T;
loop {
let start = self.pos;
let mut start = self.pos;
let kind = match self.advance()? {
b'\n' | b'\r' | b'\t' | b' ' => continue,
b'0'..=b'9' => {
@ -204,13 +205,18 @@ impl<'a> Iterator for Lexer<'a> {
}
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() {
self.advance();
}
let ident = &self.bytes[start as usize..self.pos as usize];
T::from_ident(ident)
if c == b'@' {
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':' => T::Colon,

View file

@ -153,6 +153,14 @@ impl<'a, 'b> Parser<'a, 'b> {
let frame = self.idents.len();
let token = self.next();
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 {
pos: token.start,
value: true,
@ -428,6 +436,11 @@ pub enum Expr<'a> {
pos: Pos,
value: bool,
},
Directive {
pos: u32,
name: &'a str,
args: &'a [Self],
},
}
impl<'a> Expr<'a> {
@ -436,6 +449,7 @@ impl<'a> Expr<'a> {
Self::Call { func, .. } => func.pos(),
Self::Ident { id, .. } => ident::pos(*id),
Self::Break { pos }
| Self::Directive { pos, .. }
| Self::Continue { pos }
| Self::Closure { pos, .. }
| Self::Block { pos, .. }
@ -459,18 +473,31 @@ impl<'a> std::fmt::Display for Expr<'a> {
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 {
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, .. } => {
write!(f, "struct {{")?;
let first = &mut true;
for (name, ty) in fields {
if !std::mem::take(first) {
write!(f, ", ")?;
}
write!(f, "{}: {}", name, ty)?;
}
write!(f, "}}")
fmt_list(f, "}", fields, |(name, val), f| write!(f, "{name}: {val}",))
}
Self::Ctor { ty, fields, .. } => {
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 {
write!(f, "{ty}")?;
}
write!(f, ".{}", left)?;
write!(f, ".{left}")?;
let first = &mut true;
for (name, val) in fields {
if !std::mem::take(first) {
@ -495,46 +522,33 @@ impl<'a> std::fmt::Display for Expr<'a> {
}
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::Continue { .. } => write!(f, "continue;"),
Self::If {
cond, then, else_, ..
} => {
write!(f, "if {} {}", cond, then)?;
write!(f, "if {cond} {then}")?;
if let Some(else_) = else_ {
write!(f, " else {}", else_)?;
write!(f, " else {else_}")?;
}
Ok(())
}
Self::Loop { body, .. } => write!(f, "loop {}", body),
Self::Loop { body, .. } => write!(f, "loop {body}"),
Self::Closure {
ret, body, args, ..
} => {
write!(f, "|")?;
let first = &mut true;
for arg in args {
if !std::mem::take(first) {
write!(f, ", ")?;
}
write!(f, "{}: {}", arg.name, arg.ty)?;
}
write!(f, "|: {} {}", ret, body)
write!(f, "fn(")?;
fmt_list(f, "", args, |arg, f| write!(f, "{}: {}", arg.name, arg.ty))?;
write!(f, "): {ret} {body}")
}
Self::Call { func, args } => {
write!(f, "{}(", func)?;
let first = &mut true;
for arg in args {
if !std::mem::take(first) {
write!(f, ", ")?;
}
write!(f, "{}", arg)?;
}
write!(f, ")")
write!(f, "{func}(")?;
fmt_list(f, ")", args, std::fmt::Display::fmt)
}
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::Ident { name, .. } => write!(f, "{}", name),
Self::Ident { name, .. } => write!(f, "{name}"),
Self::Block { stmts, .. } => {
writeln!(f, "{{")?;
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()) {
write!(f, " ")?;
}
writeln!(f, "{}", stmt)?;
writeln!(f, "{stmt}")?;
}
Ok(())
})();
@ -551,21 +565,21 @@ impl<'a> std::fmt::Display for Expr<'a> {
write!(f, "}}")?;
res
}
Self::Number { value, .. } => write!(f, "{}", value),
Self::Bool { value, .. } => write!(f, "{}", value),
Self::Number { value, .. } => write!(f, "{value}"),
Self::Bool { 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)
write!(f, "({expr})")
} else {
write!(f, "{}", expr)
write!(f, "{expr}")
}
};
display_branch(f, left)?;
write!(f, " {} ", op)?;
write!(f, " {op} ")?;
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;
}

View file

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