boa_engine/vm/source_info/
mod.rs1use std::{
2 fmt::Display,
3 path::{Path, PathBuf},
4 rc::Rc,
5};
6
7use boa_ast::Position;
8
9mod builder;
10
11use boa_gc::{Finalize, Trace};
12use boa_string::JsString;
13pub(crate) use builder::SourceMapBuilder;
14
15use crate::SpannedSourceText;
16
17#[cfg(test)]
18mod tests;
19
20#[derive(Debug, Default, Clone, Finalize, Trace)]
22#[boa_gc(unsafe_empty_trace)]
24pub(crate) struct SourceInfo {
25 inner: Rc<Inner>,
26}
27
28impl SourceInfo {
29 pub(crate) fn new(
30 source_map: SourceMap,
31 function_name: JsString,
32 source_text_spanned: SpannedSourceText,
33 ) -> Self {
34 Self {
35 inner: Rc::new(Inner {
36 map: source_map,
37 function_name,
38 text_spanned: source_text_spanned,
39 }),
40 }
41 }
42
43 pub(crate) fn map(&self) -> &SourceMap {
44 &self.inner.map
45 }
46
47 pub(crate) fn function_name(&self) -> &JsString {
48 &self.inner.function_name
49 }
50
51 pub(crate) fn text_spanned(&self) -> &SpannedSourceText {
52 &self.inner.text_spanned
53 }
54}
55
56#[derive(Debug, Default, Clone)]
57struct Inner {
58 map: SourceMap,
59 function_name: JsString,
60
61 text_spanned: SpannedSourceText,
62}
63
64#[derive(Debug, Default, Clone)]
66pub(crate) struct SourceMap {
67 entries: Box<[Entry]>,
68 path: SourcePath,
69}
70
71impl SourceMap {
72 pub(crate) fn new(entries: Box<[Entry]>, path: SourcePath) -> Self {
73 Self { entries, path }
74 }
75
76 pub(crate) fn entries(&self) -> &[Entry] {
77 &self.entries
78 }
79
80 pub(crate) fn find(&self, pc: u32) -> Option<Position> {
81 find_entry(self.entries(), pc)
82 }
83
84 pub(crate) fn path(&self) -> &SourcePath {
85 &self.path
86 }
87}
88
89fn find_entry(entries: &[Entry], pc: u32) -> Option<Position> {
90 let first = entries.first()?;
91
92 if pc < first.pc() {
93 return None;
94 }
95
96 let mut low = 0;
97 let mut high = entries.len() - 1;
98
99 while low <= high {
100 let mid = low.midpoint(high);
101 let entry = &entries[mid];
102 let start = entry.pc;
103
104 let end = entries.get(mid + 1).map_or(u32::MAX, |entry| entry.pc);
105
106 if pc < start {
107 high = mid;
108 } else if pc >= end {
109 low = mid + 1;
110 } else {
111 return entry.position();
112 }
113 }
114
115 entries.last().and_then(Entry::position)
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub(crate) struct Entry {
124 pub(crate) pc: u32,
129
130 pub(crate) position: Option<Position>,
132}
133
134impl Entry {
135 pub(crate) const fn pc(&self) -> u32 {
136 self.pc
137 }
138
139 pub(crate) const fn position(&self) -> Option<Position> {
140 self.position
141 }
142}
143
144#[derive(Debug, Default, Clone, PartialEq, Eq)]
146pub enum SourcePath {
147 #[default]
149 None,
150 Eval,
153 Json,
156 Path(Rc<Path>),
159}
160
161impl From<Option<PathBuf>> for SourcePath {
162 fn from(value: Option<PathBuf>) -> Self {
163 match value {
164 None => Self::None,
165 Some(path) => Self::Path(path.into()),
166 }
167 }
168}
169
170impl From<Option<Rc<Path>>> for SourcePath {
171 fn from(value: Option<Rc<Path>>) -> Self {
172 match value {
173 None => Self::None,
174 Some(path) => Self::Path(path),
175 }
176 }
177}
178
179impl Display for SourcePath {
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 match self {
182 SourcePath::None => f.write_str("unknown at "),
183 SourcePath::Eval => f.write_str("eval at "),
184 SourcePath::Json => f.write_str("json at "),
185 SourcePath::Path(path) => write!(f, "{}", path.display()),
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy)]
198pub struct NativeSourceInfo {
199 #[cfg(feature = "native-backtrace")]
200 inner: &'static std::panic::Location<'static>,
201
202 #[cfg(not(feature = "native-backtrace"))]
203 inner: std::marker::PhantomData<()>,
204}
205
206impl NativeSourceInfo {
207 #[inline]
213 #[must_use]
214 #[cfg_attr(feature = "native-backtrace", track_caller)]
215 pub const fn caller() -> Self {
216 Self {
217 #[cfg(feature = "native-backtrace")]
218 inner: std::panic::Location::caller(),
219
220 #[cfg(not(feature = "native-backtrace"))]
221 inner: std::marker::PhantomData,
222 }
223 }
224
225 #[inline]
231 #[must_use]
232 pub const fn as_location(self) -> Option<&'static std::panic::Location<'static>> {
233 #[cfg(feature = "native-backtrace")]
234 return Some(self.inner);
235
236 #[cfg(not(feature = "native-backtrace"))]
237 return None;
238 }
239}