Skip to content

Commit

Permalink
Make a relatively cursed generic router for lowering instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
DCNick3 committed Nov 2, 2023
1 parent 076ce3a commit 4ddd246
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 111 deletions.
6 changes: 3 additions & 3 deletions shin-asm/src/compile/hir/lower/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ mod tests {
───╯
Error: Unknown instruction: `x`
Error: Unrecognized instruction: `x`
╭─[test.sal:1:1]
1 │ x 96
Expand Down Expand Up @@ -359,7 +359,7 @@ mod tests {
───╯
Error: Expected no more than 2 arguments
Error: Extra argument: expected no more than 2 arguments
╭─[test.sal:1:15]
1 │ zero $v0 aslk as
Expand All @@ -386,7 +386,7 @@ mod tests {
───╯
instructions:
uo(UnaryOperation { ty: Zero, destination: $v0, source: 0 })
<error>
<error>
uo(UnaryOperation { ty: Not16, destination: $v2, source: $v1 })
code addresses:
Expand Down
2 changes: 1 addition & 1 deletion shin-asm/src/compile/hir/lower/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ mod tests {
───╯
Error: Unknown instruction: `ABOBA`
Error: Unrecognized instruction: `ABOBA`
╭─[test.sal:3:5]
3 │ ABOBA 42 42 42
Expand Down
82 changes: 37 additions & 45 deletions shin-asm/src/compile/hir/lower/instruction/from_instr_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,60 @@ use crate::compile::{
},
};

pub fn expect_no_more_args<const N: usize>(
// the non-generic part of the implementation
fn expect_opt_args_inner(
collectors: &mut FromHirCollectors,
ctx: &FromHirBlockCtx,
instr: hir::InstructionId,
) -> [Option<hir::ExprId>; N] {
let instr = ctx.instr(instr);
if instr.args.len() > N {
collectors.emit_diagnostic(
instr.args[N].into(),
format!("Expected no more than {} arguments", N),
);
}

let mut args = [None; N];
for (i, arg) in args.iter_mut().enumerate() {
*arg = instr.args.get(i).copied();
}

args
}

pub fn expect_exactly_args<const N: usize>(
collectors: &mut FromHirCollectors,
ctx: &FromHirBlockCtx,
instr: hir::InstructionId,
) -> [Option<hir::ExprId>; N] {
let instr_args = &ctx.instr(instr).args;
if instr_args.len() > N {
let msg = if N > 0 {
instr_args: &[hir::ExprId],
n_m: usize,
n_o: usize,
) {
if instr_args.len() > n_m + n_o {
let msg = if n_m + n_o > 0 {
format!(
"Extra argument: expected exactly {} arguments, but got {}",
N,
instr_args.len()
"Extra argument: expected no more than {} arguments",
n_m + n_o
)
} else {
format!(
"Extra argument: expected no arguments, but got {}",
instr_args.len()
)
format!("Extra argument: expected no arguments")
};

collectors.emit_diagnostic(instr_args[N].into(), msg);
} else if instr_args.len() < N {
collectors.emit_diagnostic(instr_args[n_m + n_o].into(), msg);
}
if instr_args.len() < n_m {
collectors.emit_diagnostic(
instr.into(),
format!(
"Missing argument: expected exactly {} arguments, but got {}",
N,
"Missing argument: expected at least {} arguments, but got {}",
n_m,
instr_args.len()
),
);
}
}

let mut args = [None; N];
for (i, arg) in args.iter_mut().enumerate() {
#[inline]
fn expect_opt_args<const N_M: usize, const N_O: usize>(
collectors: &mut FromHirCollectors,
ctx: &FromHirBlockCtx,
instr: hir::InstructionId,
) -> ([Option<hir::ExprId>; N_M], [Option<hir::ExprId>; N_O]) {
let instr_args = &ctx.instr(instr).args;
// N_M is the number of mandatory arguments
// N_O is the number of optional arguments

expect_opt_args_inner(collectors, instr, instr_args, N_M, N_O);

let mut args_m = [None; N_M];
for (i, arg) in args_m.iter_mut().enumerate() {
*arg = instr_args.get(i).copied();
}
let mut args_o = [None; N_O];
for (i, arg) in args_o.iter_mut().enumerate() {
*arg = instr_args.get(i + N_M).copied();
}

args
(args_m, args_o)
}

pub trait FromInstrArgs: Sized {
Expand Down Expand Up @@ -116,10 +111,7 @@ macro_rules! impl_from_instr_args_opt_tuple {
ctx: &FromHirBlockCtx,
instr: hir::InstructionId,
) -> Option<Self> {
let [
$($mty,)*
$($oty,)*
] = expect_no_more_args(collectors, ctx, instr);
let ([$($mty,)*], [$($oty,)*]) = expect_opt_args(collectors, ctx, instr);
$(
let $mty = $mty.and_then(|arg| {
FromHirExpr::from_hir_expr(collectors, ctx, arg)
Expand Down
86 changes: 86 additions & 0 deletions shin-asm/src/compile/hir/lower/instruction/instr_lowerer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use shin_core::format::scenario::instructions::Instruction;

use super::from_instr_args::FromInstrArgs;
use crate::compile::hir::lower::from_hir::{FromHirBlockCtx, FromHirCollectors};

pub trait InstrLowerFn<Dummy, Args: FromInstrArgs> {
fn lower_instr(
&self,
collectors: &mut FromHirCollectors,
ctx: &FromHirBlockCtx,
instr_name: &str,
args: Args,
) -> Option<Instruction>;
}

// TODO: refine the selection of the InstrLowerFn shapes

impl<
Args: FromInstrArgs,
F: Fn(&mut FromHirCollectors, &FromHirBlockCtx, &str, Args) -> Option<Instruction>,
> InstrLowerFn<((), (), (), ()), Args> for F
{
fn lower_instr(
&self,
collectors: &mut FromHirCollectors,
ctx: &FromHirBlockCtx,
instr_name: &str,
args: Args,
) -> Option<Instruction> {
self(collectors, ctx, instr_name, args)
}
}

impl<
Args: FromInstrArgs,
F: Fn(&mut FromHirCollectors, &FromHirBlockCtx, Args) -> Option<Instruction>,
> InstrLowerFn<((), (), ()), Args> for F
{
fn lower_instr(
&self,
collectors: &mut FromHirCollectors,
ctx: &FromHirBlockCtx,
_instr_name: &str,
args: Args,
) -> Option<Instruction> {
self(collectors, ctx, args)
}
}

impl<Args: FromInstrArgs, F: Fn(&str, Args) -> Option<Instruction>> InstrLowerFn<((), ()), Args>
for F
{
fn lower_instr(
&self,
_collectors: &mut FromHirCollectors,
_ctx: &FromHirBlockCtx,
instr_name: &str,
args: Args,
) -> Option<Instruction> {
self(instr_name, args)
}
}

impl<Args: FromInstrArgs, F: Fn(Args) -> Option<Instruction>> InstrLowerFn<((),), Args> for F {
fn lower_instr(
&self,
_collectors: &mut FromHirCollectors,
_ctx: &FromHirBlockCtx,
_instr_name: &str,
args: Args,
) -> Option<Instruction> {
self(args)
}
}

impl<F: Fn() -> Option<Instruction>> InstrLowerFn<(), ()> for F {
fn lower_instr(
&self,
_collectors: &mut FromHirCollectors,
_ctx: &FromHirBlockCtx,
_instr_name: &str,
_args: (),
) -> Option<Instruction> {
self()
}
}
104 changes: 42 additions & 62 deletions shin-asm/src/compile/hir/lower/instruction/mod.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,47 @@
mod from_instr_args;
mod instr_lowerer;
mod router;

use shin_core::format::scenario::{
instruction_elements::NumberSpec,
instruction_elements::{CodeAddress, NumberSpec, Register},
instructions::{Instruction, UnaryOperation, UnaryOperationType},
};

use self::router::{Router, RouterBuilder};
use crate::compile::{
hir,
hir::lower::{
from_hir::{FromHirBlockCtx, FromHirCollectors},
FromHirExpr,
},
hir::lower::from_hir::{FromHirBlockCtx, FromHirCollectors},
};

// fn zero()
fn zero((destination, source): (Register, Option<NumberSpec>)) -> Option<Instruction> {
Some(Instruction::uo(UnaryOperation {
ty: UnaryOperationType::Zero,
destination,
source: source.unwrap_or(NumberSpec::constant(0)),
}))
}

fn unary_op(
instr_name: &str,
(destination, source): (Register, NumberSpec),
) -> Option<Instruction> {
let ty = match instr_name {
"not16" => UnaryOperationType::Not16,
"neg" => UnaryOperationType::Negate,
"abs" => UnaryOperationType::Abs,
_ => unreachable!(),
};

Some(Instruction::uo(UnaryOperation {
ty,
destination,
source,
}))
}

fn jump((target,): (CodeAddress,)) -> Option<Instruction> {
Some(Instruction::j { target })
}

pub fn instruction_from_hir(
collectors: &mut FromHirCollectors,
Expand All @@ -24,63 +52,15 @@ pub fn instruction_from_hir(
return None;
};

match name.as_str() {
"zero" => {
let [destination, source] =
from_instr_args::expect_no_more_args(collectors, ctx, instr);

let destination = destination.map(|id| FromHirExpr::from_hir_expr(collectors, ctx, id));
let source = source.map(|id| FromHirExpr::from_hir_expr(collectors, ctx, id));

if destination.is_none() {
collectors.emit_diagnostic(instr.into(), "Missing a `destination` argument".into());
}
let router = RouterBuilder::new()
.add("zero", zero)
.add("not16", unary_op)
.add("neg", unary_op)
.add("abs", unary_op)
.add("j", jump)
.build();

let destination = destination??;
let source = source.flatten().unwrap_or(NumberSpec::constant(0));

Some(Instruction::uo(UnaryOperation {
ty: UnaryOperationType::Zero,
destination,
source,
}))
}
"not16" | "neg" | "abs" => {
let [destination, source] =
from_instr_args::expect_exactly_args(collectors, ctx, instr);

let destination = destination.map(|id| FromHirExpr::from_hir_expr(collectors, ctx, id));
let source = source.map(|id| FromHirExpr::from_hir_expr(collectors, ctx, id));

let destination = destination??;
let source = source??;

let ty = match name.as_str() {
"not16" => UnaryOperationType::Not16,
"neg" => UnaryOperationType::Negate,
"abs" => UnaryOperationType::Abs,
_ => unreachable!(),
};

Some(Instruction::uo(UnaryOperation {
ty,
destination,
source,
}))
}
"j" => {
let [target] = from_instr_args::expect_exactly_args(collectors, ctx, instr);
let target = target.map(|id| FromHirExpr::from_hir_expr(collectors, ctx, id));

let target = target??;

Some(Instruction::j { target })
}
_ => {
collectors.emit_diagnostic(instr.into(), format!("Unknown instruction: `{}`", name));
None
}
}
return router.handle_instr(collectors, ctx, name, instr);
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 4ddd246

Please sign in to comment.