1use super::matcher::{FuncMatcher, Match, MatchError};
4use super::vm::{Callable, Func, Script};
5use alloc::boxed::Box;
6use alloc::vec::Vec;
7use core::marker::PhantomData;
8
9pub type ModuleList<'a, C> = Box<[FuncMatcher<'a, C>]>;
11
12pub struct Cons<H, T> {
14 head: PhantomData<H>,
15 tail: PhantomData<T>,
16}
17
18pub struct Nil;
20
21pub trait ModuleType<'a, C> {
24 type Error;
25 fn compile_line(ctx: &mut C, string: &'a str) -> Result<Func<'a>, Self::Error>;
26 fn compile(ctx: &mut C, string: &'a str) -> Result<Script<'a>, (usize, Self::Error)> {
27 let mut script = Vec::new();
28 for (line_num, line) in string
29 .lines()
30 .enumerate()
31 .map(|(i, s)| (i, s.trim()))
32 .filter(|(_, s)| !s.is_empty())
33 {
34 let func = Self::compile_line(ctx, line).map_err(|e| (line_num, e))?;
35 script.push(func);
36 }
37 Ok(script.into())
38 }
39}
40
41pub trait Module<'a, C> {
44 type Error;
45 fn compile_line(&self, ctx: &mut C, string: &'a str) -> Result<Func<'a>, Self::Error>;
46 fn compile(&self, ctx: &mut C, string: &'a str) -> Result<Script<'a>, (usize, Self::Error)> {
47 let mut script = Vec::new();
48 for (line_num, line) in string
49 .lines()
50 .enumerate()
51 .map(|(i, s)| (i, s.trim()))
52 .filter(|(_, s)| !s.is_empty())
53 {
54 let func = self.compile_line(ctx, line).map_err(|e| (line_num, e))?;
55 script.push(func);
56 }
57 Ok(script.into())
58 }
59}
60
61impl<'a, H, T, C> ModuleType<'a, C> for Cons<H, T>
62where
63 H: 'a + Match<'a, C> + Callable,
64 T: ModuleType<'a, C, Error = MatchError>,
65 <T as ModuleType<'a, C>>::Error: Into<MatchError>,
66{
67 type Error = MatchError;
68 fn compile_line(ctx: &mut C, string: &'a str) -> Result<Box<dyn Callable + 'a>, Self::Error> {
69 match H::match_str(ctx, string) {
70 Ok(matched) => Ok(Box::new(matched)),
71 Err(_) => T::compile_line(ctx, string),
72 }
73 }
74}
75
76impl<'a, C> ModuleType<'a, C> for Nil {
77 type Error = MatchError;
78 fn compile_line(_: &mut C, _: &'a str) -> Result<Box<dyn Callable + 'a>, Self::Error> {
79 Err(MatchError::UnexpectedEof)
80 }
81}
82
83impl<'a, C, T> Module<'a, C> for T
84where
85 T: AsRef<[FuncMatcher<'a, C>]>,
86{
87 type Error = MatchError;
88 fn compile_line(&self, ctx: &mut C, string: &'a str) -> Result<Func<'a>, Self::Error> {
89 for match_str in self.as_ref().into_iter() {
90 if let Ok(func) = match_str(ctx, string) {
91 return Ok(func);
92 }
93 }
94 Err(MatchError::UnexpectedEof)
95 }
96}
97
98#[macro_export]
106macro_rules! mod_type {
107 () => {
108 $crate::module::Nil
109 };
110 ($head:ty) => {
111 $crate::module::Cons<$head, $crate::module::Nil>
112 };
113 ($head:ty, $($tail:ty),*) => {
114 $crate::module::Cons<$head, $crate::mod_type!($($tail),*)>
115 }
116}
117
118#[cfg(feature = "std")]
126#[macro_export]
127macro_rules! mod_list {
128 () => {
129 ::std::boxed::Box::new([])
130 };
131 ($ctx:ty => $($item:ty),*) => {
132 ::std::boxed::Box::new([$(<$item as $crate::matcher::MatchFunc<$ctx>>::match_func),*])
133 }
134}
135#[cfg(not(feature = "std"))]
136#[macro_export]
137macro_rules! mod_list {
138 () => {
139 ::alloc::boxed::Box::new([])
140 };
141 ($ctx:ty => $($item:ty),*) => {
142 ::alloc::boxed::Box::new([$(<$item as $crate::matcher::MatchFunc<$ctx>>::match_func),*])
143 }
144}