1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use super::matcher::{Match, MatchError};
use super::vm::{Callable, Func, Script};
use std::marker::PhantomData;
pub struct Cons<H, T> {
head: PhantomData<H>,
tail: PhantomData<T>,
}
pub struct Nil;
pub trait ModuleType<'a, C> {
type Error;
fn compile_line(ctx: &mut C, string: &'a str) -> Result<Func<'a>, Self::Error>;
fn compile(ctx: &mut C, string: &'a str) -> Result<Script<'a>, Self::Error> {
let mut script = Vec::new();
for line in string.lines().map(|s| s.trim()).filter(|s| !s.is_empty()) {
let func = Self::compile_line(ctx, line)?;
script.push(func);
}
Ok(script.into())
}
}
impl<'a, H, T, C> ModuleType<'a, C> for Cons<H, T>
where
H: 'a + Match<'a, C> + Callable,
T: ModuleType<'a, C, Error = MatchError>,
<T as ModuleType<'a, C>>::Error: Into<MatchError>,
{
type Error = MatchError;
fn compile_line(ctx: &mut C, string: &'a str) -> Result<Box<dyn Callable + 'a>, Self::Error> {
match H::match_str(ctx, string) {
Ok(matched) => Ok(Box::new(matched)),
Err(_) => T::compile_line(ctx, string),
}
}
}
impl<'a, C> ModuleType<'a, C> for Nil {
type Error = MatchError;
fn compile_line(_: &mut C, _: &'a str) -> Result<Box<dyn Callable + 'a>, Self::Error> {
Err(MatchError::UnexpectedEof)
}
}
#[macro_export]
macro_rules! module {
() => {
::ogma::module::Nil
};
($head:ty) => {
::ogma::module::Cons<$head, ::ogma::module::Nil>
};
($head:ty, $($tail:ty),*) => {
::ogma::module::Cons<$head, ::ogma::module!($($tail),*)>
}
}