1use crate::{compile::TermId, filter::Vars, RcList};
4use alloc::{boxed::Box, string::String, string::ToString, vec::Vec};
5use core::fmt::{self, Display};
6
7#[derive(Clone, Debug)]
14pub struct Exn<'a, V>(pub(crate) Inner<'a, V>);
15
16#[derive(Clone, Debug)]
17pub(crate) enum Inner<'a, V> {
18 Err(Box<Error<V>>),
19 TailCall(Box<(&'a TermId, Vars<V>, CallInput<V>)>),
24 Break(usize),
25 Halt(i32),
26}
27
28#[derive(Clone, Debug)]
29pub(crate) enum CallInput<V> {
30 Run(V),
31 Paths((V, RcList<V>)),
32}
33
34impl<V> CallInput<V> {
35 pub fn unwrap_run(self) -> V {
36 match self {
37 Self::Run(v) => v,
38 _ => panic!(),
39 }
40 }
41
42 pub fn unwrap_paths(self) -> (V, RcList<V>) {
43 match self {
44 Self::Paths(vp) => vp,
45 _ => panic!(),
46 }
47 }
48}
49
50impl<V> Exn<'_, V> {
51 pub fn get_err(self) -> Result<Error<V>, Self> {
53 match self.0 {
54 Inner::Err(e) => Ok(*e),
55 _ => Err(self),
56 }
57 }
58
59 pub fn get_halt(self) -> Result<i32, Self> {
61 match self.0 {
62 Inner::Halt(code) => Ok(code),
63 _ => Err(self),
64 }
65 }
66
67 pub fn halt(exit_code: i32) -> Self {
71 Self(Inner::Halt(exit_code))
72 }
73}
74
75impl<V> From<Error<V>> for Exn<'_, V> {
76 fn from(e: Error<V>) -> Self {
77 Exn(Inner::Err(Box::new(e)))
78 }
79}
80
81#[derive(Clone, Debug, PartialEq, Eq)]
82enum Part<V, S = &'static str> {
83 Val(V),
84 Str(S),
85}
86
87#[derive(Clone, Debug, PartialEq, Eq)]
89pub struct Error<V>(Part<V, Vec<Part<V>>>);
90
91impl<V> Error<V> {
92 pub fn new(v: V) -> Self {
94 Self(Part::Val(v))
95 }
96
97 pub fn path_expr(v: V) -> Self {
99 Self(Part::Str(Vec::from([
100 Part::Str("invalid path expression with input "),
101 Part::Val(v),
102 ])))
103 }
104
105 pub fn typ(v: V, typ: &'static str) -> Self {
107 use Part::{Str, Val};
108 [Str("cannot use "), Val(v), Str(" as "), Str(typ)]
109 .into_iter()
110 .collect()
111 }
112
113 pub fn math(l: V, op: crate::ops::Math, r: V) -> Self {
115 use Part::{Str, Val};
116 [
117 Str("cannot calculate "),
118 Val(l),
119 Str(" "),
120 Str(op.as_str()),
121 Str(" "),
122 Val(r),
123 ]
124 .into_iter()
125 .collect()
126 }
127
128 pub fn index(l: V, r: V) -> Self {
130 use Part::{Str, Val};
131 [Str("cannot index "), Val(l), Str(" with "), Val(r)]
132 .into_iter()
133 .collect()
134 }
135}
136
137impl<V: From<String>> Error<V> {
138 pub fn str(s: impl ToString) -> Self {
140 Self(Part::Val(V::from(s.to_string())))
141 }
142}
143
144impl<V> FromIterator<Part<V>> for Error<V> {
145 fn from_iter<T: IntoIterator<Item = Part<V>>>(iter: T) -> Self {
146 Self(Part::Str(iter.into_iter().collect()))
147 }
148}
149
150impl<V: From<String> + Display> Error<V> {
151 pub fn into_val(self) -> V {
153 if let Part::Val(v) = self.0 {
154 v
155 } else {
156 V::from(self.to_string())
157 }
158 }
159}
160
161impl<V: Display> Display for Error<V> {
162 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163 match &self.0 {
164 Part::Val(v) => v.fmt(f),
165 Part::Str(parts) => parts.iter().try_for_each(|part| match part {
166 Part::Val(v) => v.fmt(f),
167 Part::Str(s) => s.fmt(f),
168 }),
169 }
170 }
171}