1use std::{fmt, sync::Arc};
2
3use openpine_compiler::{CompileErrors, loader::ModuleKind};
4use openpine_error::{ErrorWithSourceFile, SourceFile};
5use openpine_visitor::ast::{Position, Span};
6
7use crate::{CreateSymbolInfoError, TimeFrame, TradeSession, context::ModuleFrame};
8
9#[derive(Debug, Clone)]
11pub struct BacktraceFrame {
12 pub func_name: Option<String>,
15 pub span: Span,
19 pub module_kind: ModuleKind,
21}
22
23#[derive(Debug, Clone, Default)]
25pub struct Backtrace {
26 pub frames: Vec<BacktraceFrame>,
28 pub source_files: Arc<[SourceFile<String, String>]>,
30}
31
32impl fmt::Display for Backtrace {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 writeln!(f, "call stack (most recent call last):")?;
35 for (i, frame) in self.frames.iter().enumerate() {
36 let file_id = frame.span.start.file_id as usize;
37 let path = self
38 .source_files
39 .get(file_id)
40 .map(|sf| sf.path.as_str())
41 .unwrap_or("<unknown>");
42 let name = frame.func_name.as_deref().unwrap_or("<root>");
43 writeln!(
44 f,
45 " #{i}: {name} at {path}:{line}:{col}",
46 line = frame.span.start.line,
47 col = frame.span.start.column,
48 )?;
49 }
50 Ok(())
51 }
52}
53
54#[derive(Debug, thiserror::Error)]
56#[error("{}", error.error.message)]
57#[non_exhaustive]
58pub struct Exception {
59 error: ErrorWithSourceFile<Span, Arc<[SourceFile<String, String>]>>,
60 backtrace_frames: Vec<ModuleFrame>,
61}
62
63impl Exception {
64 #[inline]
65 pub(crate) fn new(
66 error: ErrorWithSourceFile<Span, Arc<[SourceFile<String, String>]>>,
67 backtrace_frames: Vec<ModuleFrame>,
68 ) -> Self {
69 Self {
70 error,
71 backtrace_frames,
72 }
73 }
74
75 #[inline]
77 pub fn display(&self) -> openpine_error::ErrorDisplay<'_, Span, String, String> {
78 self.error.error.display(&self.error.source_files)
79 }
80
81 #[inline]
83 pub fn message(&self) -> &str {
84 &self.error.error.message
85 }
86
87 #[inline]
89 pub fn first_span(&self) -> Option<&Span> {
90 self.error.error.spans.first()
91 }
92
93 pub fn backtrace(&self) -> Backtrace {
96 Backtrace {
97 frames: self
98 .backtrace_frames
99 .iter()
100 .map(|f| {
101 let span = f.entry_span.unwrap_or_else(|| {
102 Span::new(
103 Position::new(f.file_id, 1, 1, 0),
104 Position::new(f.file_id, 1, 1, 0),
105 )
106 });
107 BacktraceFrame {
108 func_name: f.func_name.clone(),
109 span,
110 module_kind: f.module_kind,
111 }
112 })
113 .collect(),
114 source_files: self.error.source_files.clone(),
115 }
116 }
117}
118
119#[derive(Debug, thiserror::Error)]
122#[non_exhaustive]
123pub enum Error {
124 #[error(transparent)]
126 Compile(#[from] CompileErrors),
127 #[error("missing script type")]
129 MissingScriptType,
130 #[error("input value not found for id `{0}`")]
132 InputValueNotFound(usize),
133 #[error("failed to serialize input value for id `{0}`: {1}")]
135 SetInputValue(usize, String),
136 #[error("unsupported time frame: {0}")]
138 UnsupportedTimeFrame(TimeFrame),
139 #[error("trade session not allowed: {0:?}")]
141 SessionNotAllowed(TradeSession),
142 #[error(transparent)]
144 CreateSymbolInfo(#[from] CreateSymbolInfoError),
145 #[error(transparent)]
147 Exception(#[from] Exception),
148 #[error("library scripts cannot be executed")]
150 LibraryScriptNotExecutable,
151 #[error("data provider error: {0}")]
153 DataProvider(String),
154}