1pub mod bytecodegen;
2pub(crate) mod intrinsics;
3pub mod mirgen;
4pub mod parser;
5pub mod typing;
6use crate::plugin::{ExtFunTypeInfo, MacroFunction};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum EvalStage {
12 Persistent,
14 Stage(u8),
16}
17
18impl std::fmt::Display for EvalStage {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match self {
21 EvalStage::Persistent => write!(f, "persistent"),
22 EvalStage::Stage(n) => write!(f, "{}", n),
23 }
24 }
25}
26
27impl EvalStage {
28 pub fn is_available_in_macro(&self) -> bool {
29 matches!(self, EvalStage::Persistent | EvalStage::Stage(0))
30 }
31 pub fn is_available_in_vm(&self) -> bool {
32 matches!(self, EvalStage::Persistent | EvalStage::Stage(1))
33 }
34
35 pub fn format_for_error(&self) -> String {
37 match self {
38 EvalStage::Persistent => "persistent".to_string(),
39 EvalStage::Stage(n) => n.to_string(),
40 }
41 }
42
43 pub fn increment(self) -> EvalStage {
45 match self {
46 EvalStage::Persistent => EvalStage::Persistent, EvalStage::Stage(n) => EvalStage::Stage(n + 1),
48 }
49 }
50
51 pub fn decrement(self) -> EvalStage {
53 match self {
54 EvalStage::Persistent => EvalStage::Persistent, EvalStage::Stage(n) => EvalStage::Stage(n.saturating_sub(1)),
56 }
57 }
58}
59
60#[derive(Debug, Clone)]
61pub enum ErrorKind {
62 TypeMismatch(Type, Type),
63 CircularType,
64 IndexOutOfRange(u16, u16),
65 IndexForNonTuple(Type),
66 VariableNotFound(String),
67 NonPrimitiveInFeed,
68 NotApplicable, IndexOutOfBounds,
70 TypeError,
71 Unknown,
72}
73#[derive(Debug, Clone)]
74pub struct Error(pub ErrorKind, pub Span);
75
76impl std::fmt::Display for ErrorKind {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 match self {
79 ErrorKind::VariableNotFound(_) => {
80 write!(f, "Variable Not Found.")
81 }
82 ErrorKind::TypeMismatch(expect, actual) => {
83 write!(
84 f,
85 "Type Mismatch, expected {expect}, but the actual was {actual}."
86 )
87 }
88 ErrorKind::IndexForNonTuple(t) => {
89 write!(f, "Index access for non tuple-type {t}.")
90 }
91 ErrorKind::IndexOutOfRange(r, a) => {
92 write!(
93 f,
94 "Tuple index out of range, number of elements are {r} but accessed with {a}."
95 )
96 }
97 ErrorKind::NotApplicable => {
98 write!(f, "Application to non-function type value.")
99 }
100 ErrorKind::CircularType => write!(f, "Circular loop of type definition"),
101 ErrorKind::NonPrimitiveInFeed => write!(f, "Feed can take only non-funtion type."),
102 ErrorKind::IndexOutOfBounds => write!(f, "Array index out of bounds."),
103 ErrorKind::TypeError => write!(f, "Type error in expression."),
104 ErrorKind::Unknown => write!(f, "unknwon error."),
105 }
106 }
107}
108impl std::fmt::Display for Error {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 self.0.fmt(f)
111 }
112}
113
114impl std::error::Error for Error {}
115
116impl ReportableError for Error {
117 fn get_labels(&self) -> Vec<(crate::utils::metadata::Location, String)> {
118 todo!()
119 }
120}
121
122use std::path::PathBuf;
123
124use mirgen::recursecheck;
125
126use crate::{
127 interner::{ExprNodeId, Symbol, TypeNodeId},
128 mir::Mir,
129 runtime::vm,
130 types::Type,
131 utils::{error::ReportableError, metadata::Span},
132};
133pub fn emit_ast(
134 src: &str,
135 path: Option<PathBuf>,
136) -> Result<ExprNodeId, Vec<Box<dyn ReportableError>>> {
137 let (ast, errs) = parser::parse_to_expr(src, path.clone());
138 if errs.is_empty() {
139 let ast = parser::add_global_context(ast, path.clone().unwrap_or_default());
140 let (ast, _errs) =
141 mirgen::convert_pronoun::convert_pronoun(ast, path.clone().unwrap_or_default());
142 Ok(recursecheck::convert_recurse(
143 ast,
144 path.clone().unwrap_or_default(),
145 ))
146 } else {
147 Err(errs)
148 }
149}
150
151#[derive(Clone, Copy, Debug, Default)]
152pub struct Config {
153 pub self_eval_mode: bytecodegen::SelfEvalMode,
154}
155
156pub struct Context {
157 ext_fns: Vec<ExtFunTypeInfo>,
158 macros: Vec<Box<dyn MacroFunction>>,
159 file_path: Option<PathBuf>,
160 config: Config,
161}
162unsafe impl Send for Context {}
164
165#[derive(Debug, Clone, Copy, Default, PartialEq)]
166pub struct IoChannelInfo {
167 pub input: u32,
168 pub output: u32,
169}
170
171impl Context {
172 pub fn new(
173 ext_fns: impl IntoIterator<Item = ExtFunTypeInfo>,
174 macros: impl IntoIterator<Item = Box<dyn MacroFunction>>,
175 file_path: Option<PathBuf>,
176 config: Config,
177 ) -> Self {
178 Self {
179 ext_fns: ext_fns.into_iter().collect(),
180 macros: macros.into_iter().collect(),
181 file_path,
182 config,
183 }
184 }
185 pub fn get_ext_typeinfos(&self) -> Vec<(Symbol, TypeNodeId)> {
186 self.ext_fns
187 .clone()
188 .into_iter()
189 .map(|ExtFunTypeInfo { name, ty, .. }| (name, ty))
190 .chain(self.macros.iter().map(|m| (m.get_name(), m.get_type())))
191 .collect()
192 }
193 pub fn emit_mir(&self, src: &str) -> Result<Mir, Vec<Box<dyn ReportableError>>> {
194 let path = self.file_path.clone();
195 let (ast, mut parse_errs) = parser::parse_to_expr(src, path);
196 let mir = mirgen::compile(
198 ast,
199 self.get_ext_typeinfos().as_slice(),
200 &self.macros,
201 self.file_path.clone(),
202 );
203 if parse_errs.is_empty() {
204 mir
205 } else {
206 let _ = mir.map_err(|mut e| {
207 parse_errs.append(&mut e);
208 });
209 Err(parse_errs)
210 }
211 }
212 pub fn emit_bytecode(&self, src: &str) -> Result<vm::Program, Vec<Box<dyn ReportableError>>> {
213 let mir = self.emit_mir(src)?;
214 let config = bytecodegen::Config {
215 self_eval_mode: self.config.self_eval_mode,
216 };
217 Ok(bytecodegen::gen_bytecode(mir, config))
218 }
219}
220
221#[cfg(test)]
233mod test {
234 use crate::{
235 function,
236 interner::ToSymbol,
237 numeric,
238 types::{PType, Type},
239 };
240
241 use super::*;
242 fn get_source() -> &'static str {
243 r#"
246fn counter(){
247 self + 1
248}
249fn dsp(input:float){
250 let res = input + counter()
251 (0,res)
252}
253"#
254 }
255 fn test_context() -> Context {
256 let addfn = ExtFunTypeInfo::new(
257 "add".to_symbol(),
258 function!(vec![numeric!(), numeric!()], numeric!()),
259 EvalStage::Persistent,
260 );
261 let extfns = [addfn];
262 Context::new(extfns, [], None, Config::default())
263 }
264 #[test]
265 fn mir_channelcount() {
266 let src = &get_source();
267 let ctx = test_context();
268 let mir = ctx.emit_mir(src).unwrap();
269 log::trace!("Mir: {mir}");
270 let iochannels = mir.get_dsp_iochannels().unwrap();
271 assert_eq!(iochannels.input, 1);
272 assert_eq!(iochannels.output, 2);
273 }
274 #[test]
275 fn bytecode_channelcount() {
276 let src = &get_source();
277 let ctx = test_context();
278 let prog = ctx.emit_bytecode(src).unwrap();
279 let iochannels = prog.iochannels.unwrap();
280 assert_eq!(iochannels.input, 1);
281 assert_eq!(iochannels.output, 2);
282 }
283}