1use std::any::{Any, TypeId};
2use std::collections::HashMap;
3use std::sync::Arc;
4
5use crate::models::error::Error;
6use crate::models::file::File;
7use crate::models::nlcst::Node;
8use crate::models::position::Position;
9use crate::models::tree::{Tree, TreeKind};
10use crate::{Allocator, ArenaVec};
11
12pub trait Plugin: Send + Sync {
14 fn attach(&self, context: &mut Attach) -> Result<(), Error>;
15}
16
17pub trait Parser: Send + Sync {
19 fn output(&self) -> TreeKind;
20
21 fn source<'a>(&self, input: &'a str) -> &'a str {
23 input
24 }
25
26 fn parse<'a>(
27 &self,
28 input: &'a str,
29 file: &mut File,
30 alloc: &'a Allocator,
31 ) -> Result<Tree<'a>, Error>;
32}
33
34pub trait Transform: Send + Sync {
36 fn input(&self) -> TreeKind;
37 fn output(&self) -> TreeKind;
38 fn run<'a>(
39 &self,
40 tree: Tree<'a>,
41 file: &mut File,
42 alloc: &'a Allocator,
43 ) -> Result<Tree<'a>, Error>;
44
45 fn start<'a>(
47 &self,
48 tree: Tree<'a>,
49 file: &mut File,
50 alloc: &'a Allocator,
51 ) -> Result<Step<'a>, Error> {
52 self.run(tree, file, alloc).map(Step::Done)
53 }
54
55 fn host(&self) -> Option<u32> {
58 None
59 }
60}
61
62pub type Job<'a> = Box<dyn FnOnce(&mut File) -> Result<Tree<'a>, Error> + 'a>;
64
65pub enum Step<'a> {
67 Done(Tree<'a>),
68 Job(Job<'a>),
69}
70
71pub trait Compiler: Send + Sync {
73 fn input(&self) -> TreeKind;
74 fn extension(&self) -> &'static str;
75 fn compile(&self, tree: &Tree<'_>, file: &mut File) -> Result<String, Error>;
76}
77
78pub trait NaturalLanguageParser: Send + Sync {
81 fn tokenize<'a>(
84 &self,
85 value: &'a str,
86 offset: usize,
87 alloc: &'a Allocator,
88 ) -> ArenaVec<'a, Node<'a>>;
89
90 fn tokenize_paragraph<'a>(
94 &self,
95 content: ArenaVec<'a, Node<'a>>,
96 position: Option<Position<'a>>,
97 alloc: &'a Allocator,
98 ) -> Node<'a>;
99
100 fn tokenize_root<'a>(
103 &self,
104 paragraph: Node<'a>,
105 position: Option<Position<'a>>,
106 alloc: &'a Allocator,
107 ) -> Node<'a>;
108}
109
110#[derive(Clone, Default)]
113pub struct NaturalLanguageParserSlot {
114 pub parser: Option<Arc<dyn NaturalLanguageParser>>,
115}
116
117pub trait ScriptParser: Send + Sync {
120 fn parse_expression(&self, source: &str) -> Result<ScriptExpression, ScriptError>;
123
124 fn parse_module(&self, source: &str) -> Result<Vec<ScriptStatement>, ScriptError>;
126}
127
128#[derive(Clone, Debug, PartialEq, Eq)]
132pub struct ScriptExpression {
133 pub end: usize,
134 pub object: Option<Vec<(String, usize)>>,
135}
136
137#[derive(Clone, Debug, PartialEq, Eq)]
140pub struct ScriptStatement {
141 pub kind: String,
142 pub offset: usize,
143 pub imports: Vec<String>,
144}
145
146#[derive(Clone, Debug, PartialEq, Eq)]
149pub struct ScriptError {
150 pub start: usize,
151 pub end: usize,
152 pub reason: String,
153}
154
155#[derive(Clone, Default)]
159pub struct ScriptParserSlot {
160 pub parser: Option<Arc<dyn ScriptParser>>,
161}
162
163type ParserFactory = Box<dyn FnOnce(&Slots) -> Result<Box<dyn Parser>, Error>>;
164type CompilerFactory = Box<dyn FnOnce(&Slots) -> Result<Box<dyn Compiler>, Error>>;
165
166#[derive(Default)]
168pub struct Attach {
169 parser: Option<ParserFactory>,
170 compiler: Option<CompilerFactory>,
171 transforms: Vec<Box<dyn Transform>>,
172 slots: Slots,
173}
174
175#[derive(Default)]
177pub struct Slots {
178 values: HashMap<TypeId, Box<dyn Any>>,
179}
180
181impl Attach {
182 pub fn set_parser(
184 &mut self,
185 factory: impl FnOnce(&Slots) -> Result<Box<dyn Parser>, Error> + 'static,
186 ) {
187 self.parser = Some(Box::new(factory));
188 }
189
190 pub fn set_compiler(
192 &mut self,
193 factory: impl FnOnce(&Slots) -> Result<Box<dyn Compiler>, Error> + 'static,
194 ) {
195 self.compiler = Some(Box::new(factory));
196 }
197
198 pub fn add_transform(&mut self, transform: Box<dyn Transform>) {
199 self.transforms.push(transform);
200 }
201
202 pub fn slots_mut(&mut self) -> &mut Slots {
203 &mut self.slots
204 }
205
206 #[allow(clippy::type_complexity)]
208 pub fn finish(
209 self,
210 ) -> Result<
211 (
212 Option<Box<dyn Parser>>,
213 Vec<Box<dyn Transform>>,
214 Option<Box<dyn Compiler>>,
215 ),
216 Error,
217 > {
218 let parser = self
219 .parser
220 .map(|factory| factory(&self.slots))
221 .transpose()?;
222 let compiler = self
223 .compiler
224 .map(|factory| factory(&self.slots))
225 .transpose()?;
226 Ok((parser, self.transforms, compiler))
227 }
228}
229
230impl Slots {
231 pub fn get<T: 'static>(&self) -> Option<&T> {
232 self.values
233 .get(&TypeId::of::<T>())
234 .and_then(|value| value.downcast_ref())
235 }
236
237 pub fn get_or_default<T: Default + 'static>(&mut self) -> &mut T {
238 let value = self
239 .values
240 .entry(TypeId::of::<T>())
241 .or_insert_with(|| Box::new(T::default()));
242 match value.downcast_mut() {
243 Some(value) => value,
244 None => unreachable!("a slot holds the type it is keyed by"),
245 }
246 }
247}