rune/runtime/
debug.rs

1//! Debug information for units.
2
3use core::fmt;
4
5use serde::{Deserialize, Serialize};
6
7use crate as rune;
8use crate::alloc::prelude::*;
9use crate::alloc::{Box, HashMap, Vec};
10use crate::ast::Span;
11use crate::runtime::DebugLabel;
12use crate::{Hash, ItemBuf, SourceId};
13
14/// Debug information about a unit.
15#[derive(Debug, TryClone, Default, Serialize, Deserialize)]
16#[non_exhaustive]
17pub struct DebugInfo {
18    /// Debug information on each instruction.
19    pub instructions: HashMap<usize, DebugInst>,
20    /// Function signatures.
21    pub functions: HashMap<Hash, DebugSignature>,
22    /// Reverse lookup of a function.
23    pub functions_rev: HashMap<usize, Hash>,
24    /// Hash to identifier.
25    pub hash_to_ident: HashMap<Hash, Box<str>>,
26}
27
28impl DebugInfo {
29    /// Get debug instruction at the given instruction pointer.
30    pub fn instruction_at(&self, ip: usize) -> Option<&DebugInst> {
31        self.instructions.get(&ip)
32    }
33
34    /// Get the function corresponding to the given instruction pointer.
35    pub fn function_at(&self, ip: usize) -> Option<(Hash, &DebugSignature)> {
36        let hash = *self.functions_rev.get(&ip)?;
37        let signature = self.functions.get(&hash)?;
38        Some((hash, signature))
39    }
40
41    /// Access an identifier for the given hash - if it exists.
42    pub fn ident_for_hash(&self, hash: Hash) -> Option<&str> {
43        Some(self.hash_to_ident.get(&hash)?)
44    }
45}
46
47/// Debug information for every instruction.
48#[derive(Debug, TryClone, Serialize, Deserialize)]
49#[non_exhaustive]
50pub struct DebugInst {
51    /// The file by id the instruction belongs to.
52    pub source_id: SourceId,
53    /// The span of the instruction.
54    pub span: Span,
55    /// The comment for the line.
56    pub comment: Option<Box<str>>,
57    /// Label associated with the location.
58    pub labels: Vec<DebugLabel>,
59}
60
61impl DebugInst {
62    /// Construct a new debug instruction.
63    pub fn new(
64        source_id: SourceId,
65        span: Span,
66        comment: Option<Box<str>>,
67        labels: Vec<DebugLabel>,
68    ) -> Self {
69        Self {
70            source_id,
71            span,
72            comment,
73            labels,
74        }
75    }
76}
77
78/// Debug information on function arguments.
79#[derive(Debug, TryClone, Serialize, Deserialize)]
80pub enum DebugArgs {
81    /// An empty, with not arguments.
82    EmptyArgs,
83    /// A tuple, with the given number of arguments.
84    TupleArgs(usize),
85    /// A collection of named arguments.
86    Named(Box<[Box<str>]>),
87}
88
89/// A description of a function signature.
90#[derive(Debug, TryClone, Serialize, Deserialize)]
91#[non_exhaustive]
92pub struct DebugSignature {
93    /// The path of the function.
94    pub path: ItemBuf,
95    /// The number of arguments expected in the function.
96    pub args: DebugArgs,
97}
98
99impl DebugSignature {
100    /// Construct a new function signature.
101    pub fn new(path: ItemBuf, args: DebugArgs) -> Self {
102        Self { path, args }
103    }
104}
105
106impl fmt::Display for DebugSignature {
107    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
108        match &self.args {
109            DebugArgs::EmptyArgs => {
110                write!(fmt, "{}", self.path)?;
111            }
112            DebugArgs::TupleArgs(args) if *args > 0 => {
113                write!(fmt, "{}(", self.path)?;
114
115                let mut it = 0..*args;
116                let last = it.next_back();
117
118                for arg in it {
119                    write!(fmt, "{}, ", arg)?;
120                }
121
122                if let Some(arg) = last {
123                    write!(fmt, "{}", arg)?;
124                }
125
126                write!(fmt, ")")?;
127            }
128            DebugArgs::Named(args) => {
129                write!(fmt, "{}(", self.path)?;
130
131                let mut it = args.iter();
132                let last = it.next_back();
133
134                for arg in it {
135                    write!(fmt, "{}, ", arg)?;
136                }
137
138                if let Some(arg) = last {
139                    write!(fmt, "{}", arg)?;
140                }
141
142                write!(fmt, ")")?;
143            }
144            _ => (),
145        }
146
147        Ok(())
148    }
149}