Skip to main content

cambridge_asm/exec/
inst.rs

1// Copyright (c) 2021 Saadi Save
2// This Source Code Form is subject to the terms of the Mozilla Public
3// License, v. 2.0. If a copy of the MPL was not distributed with this
4// file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6use crate::{
7    exec::{Context, RtResult},
8    inst::Op,
9};
10
11/// Function pointer of an instruction called with [`Context`] and [`Op`] at runtime
12pub type ExecFunc = fn(&mut Context, &Op) -> RtResult;
13
14/// Runtime representation of an instruction
15#[derive(Clone)]
16pub struct ExecInst {
17    /// Identifies the instruction with an integer, fixes rust-lang/rfcs#3535
18    pub id: u64,
19    pub func: ExecFunc,
20    pub op: Op,
21}
22
23impl ExecInst {
24    pub fn new(id: u64, inst: ExecFunc, op: Op) -> Self {
25        Self { func: inst, op, id }
26    }
27}
28
29/// Macro to generate an instruction implementation
30///
31/// # Examples
32/// ```
33/// use cambridge_asm::inst;
34///
35/// // No Context
36/// inst!(name1 { /* Do something that doesn't need context or op*/ });
37///
38/// // Context only
39/// inst!(name3 (ctx) { /* Do something with ctx */ });
40///
41/// // Context and op
42/// inst!(name5 (ctx, op) { /* Do something with ctx and op */ });
43/// ```
44///
45/// For further reference, look at the source of the module [`super::io`]
46#[macro_export]
47macro_rules! inst {
48    ($(#[$outer:meta])* $vis:vis $name:ident ($ctx:ident, $op:ident) { $( $code:tt )* }) => {
49        $(#[$outer])*
50        $vis fn $name($ctx: &mut $crate::exec::Context, $op: & $crate::inst::Op) -> $crate::exec::RtResult {
51            use $crate::inst::Op::*;
52            $( $code )*
53            Ok(())
54        }
55    };
56    ($(#[$outer:meta])* $vis:vis $name:ident ($ctx:ident) { $( $code:tt )* }) => {
57        $(#[$outer])*
58        $vis fn $name($ctx: &mut $crate::exec::Context, _: & $crate::inst::Op) -> $crate::exec::RtResult {
59            $( $code )*
60            Ok(())
61        }
62    };
63    ($(#[$outer:meta])* $vis:vis $name:ident { $( $code:tt )* }) => {
64        $(#[$outer])*
65        $vis fn $name(_: &mut $crate::exec::Context, _: & $crate::inst::Op) -> $crate::exec::RtResult {
66            $( $code )*
67            Ok(())
68        }
69    };
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use crate::inst::Op::*;
76
77    #[test]
78    fn op_parsing() {
79        let ops = [
80            ("200", Addr(200)),
81            ("#x80", Literal(128)),
82            ("#b001", Literal(1)),
83            ("#800", Literal(800)),
84            (
85                "200,#8,be",
86                MultiOp(vec![Addr(200), Literal(8), Fail("be".into())]),
87            ),
88            ("", Null),
89            ("ACC,r10,#x10", MultiOp(vec![Acc, Gpr(10), Literal(16)])),
90        ];
91
92        for (op, res) in ops {
93            assert_eq!(Op::from(op), res);
94        }
95    }
96}