1use crate::commands::primitives::{PrimitiveIdentifier, PRIMITIVES};
6use crate::engine::filesystem::SourceReference;
7use crate::engine::filesystem::{File, FileLineSource};
8use crate::engine::mouth::strings::{InputTokenizer, MouthState};
9use crate::engine::state::State;
10use crate::engine::utils::outputs::Outputs;
11use crate::engine::{EngineAux, EngineReferences, EngineTypes};
12use crate::prelude::{CommandCode, TokenList};
13use crate::tex::catcodes::CategoryCodeScheme;
14use crate::tex::characters::StringLineSource;
15use crate::tex::tokens::control_sequences::CSName;
16use crate::tex::tokens::token_lists::MacroExpansion;
17use crate::tex::tokens::Token;
18use crate::utils::errors::{InvalidCharacter, RecoverableError, TeXError, TeXResult};
19
20pub mod strings;
21
22pub trait Mouth<ET: EngineTypes> {
38 fn new(aux: &mut EngineAux<ET>, state: &mut ET::State) -> Self;
40 fn push_file(&mut self, f: ET::File);
42 fn push_string(&mut self, s: StringLineSource<ET::Char>);
44 fn push_exp(&mut self, exp: &TokenList<ET::Token>);
46 fn push_vec(&mut self, exp: Vec<ET::Token>);
48 fn push_slice_rev(&mut self, exp: &[ET::Token]);
51 fn push_macro_exp(&mut self, exp: MacroExpansion<ET::Token>);
54 fn requeue(&mut self, t: ET::Token);
59 fn get_next(
64 &mut self,
65 aux: &mut EngineAux<ET>,
66 state: &ET::State,
67 ) -> Result<Option<ET::Token>, InvalidCharacter<ET::Char>>;
68 fn iterate<R, E, F: FnMut(&mut EngineAux<ET>, ET::Token) -> TeXResult<Option<R>, ET>>(
76 &mut self,
77 aux: &mut EngineAux<ET>,
78 state: &ET::State,
79 cont: F,
80 eof: E,
81 ) -> TeXResult<R, ET>
82 where
83 E: Fn(&EngineAux<ET>, &ET::State, &mut Self) -> TeXResult<(), ET>;
84 fn endinput(
88 &mut self,
89 aux: &mut EngineAux<ET>,
90 state: &ET::State,
91 ) -> Result<(), InvalidCharacter<ET::Char>>;
92 fn finish(&mut self);
94
95 fn current_sourceref(&self) -> SourceReference<<ET::File as File>::SourceRefID>;
97 fn start_ref(&self) -> SourceReference<<ET::File as File>::SourceRefID>;
104 fn update_start_ref(&mut self);
106 fn line_number(&self) -> usize;
108 fn get_args(&mut self) -> [Vec<ET::Token>; 9];
112 fn return_args(&mut self, args: [Vec<ET::Token>; 9]);
115
116 fn read_until_endgroup<E, F: FnMut(&mut EngineAux<ET>, ET::Token) -> TeXResult<(), ET>>(
122 &mut self,
123 aux: &mut EngineAux<ET>,
124 state: &ET::State,
125 mut cont: F,
126 eof: E,
127 ) -> TeXResult<ET::Token, ET>
128 where
129 E: Fn(&EngineAux<ET>, &ET::State, &mut Self) -> TeXResult<(), ET>,
130 {
131 let mut ingroups = 0;
132 self.iterate(
133 aux,
134 state,
135 |a, t| {
136 match t.command_code() {
137 CommandCode::BeginGroup => ingroups += 1,
138 CommandCode::EndGroup => {
139 if ingroups == 0 {
140 return Ok(Some(t));
141 }
142 ingroups -= 1;
143 }
144 CommandCode::Primitive if t.is_primitive() == Some(PRIMITIVES.noexpand) => {
145 return Ok(None)
146 }
147 _ => (),
148 }
149 cont(a, t)?;
150 Ok(None)
151 },
152 eof,
153 )
154 }
155
156 fn preview(
158 &self,
159 int: &<ET::CSName as CSName<ET::Char>>::Handler,
160 cc: &CategoryCodeScheme<ET::Char>,
161 esc: Option<ET::Char>,
162 ) -> String;
163
164 fn file_trace(
165 &self,
166 ) -> impl Iterator<Item = SourceReference<<ET::File as File>::SourceRefID>> + '_;
167}
168
169enum TokenSource<T: Token, F: File<Char = T::Char>> {
170 String(InputTokenizer<T::Char, StringLineSource<T::Char>>),
171 File(InputTokenizer<T::Char, F::LineSource>, F::SourceRefID),
172 Vec(Vec<T>),
173}
174
175pub struct DefaultMouth<ET: EngineTypes> {
182 inputs: Vec<TokenSource<ET::Token, ET::File>>,
183 args: Option<[Vec<ET::Token>; 9]>,
184 start_ref: Vec<SourceReference<<ET::File as File>::SourceRefID>>,
185 vecs: Vec<Vec<ET::Token>>,
186}
187
188impl<ET: EngineTypes> Mouth<ET> for DefaultMouth<ET> {
189 fn new(_aux: &mut EngineAux<ET>, _state: &mut ET::State) -> Self {
190 Self {
191 inputs: Vec::new(),
192 args: Some(array_init::array_init(|_| Vec::new())),
193 start_ref: vec![],
194 vecs: vec![],
195 }
196 }
197
198 fn finish(&mut self) {
199 for s in self.inputs.drain(..) {
200 if let TokenSource::Vec(mut v) = s {
201 v.clear();
202 self.vecs.push(v);
203 }
204 }
205 self.start_ref.clear();
206 }
207
208 fn file_trace(
209 &self,
210 ) -> impl Iterator<Item = SourceReference<<ET::File as File>::SourceRefID>> + '_ {
211 self.inputs.iter().rev().filter_map(|s| {
212 if let TokenSource::File(f, id) = s {
213 Some(SourceReference {
214 file: *id,
215 line: f.line(),
216 column: f.column(),
217 })
218 } else {
219 None
220 }
221 })
222 }
223
224 fn current_sourceref(&self) -> SourceReference<<ET::File as File>::SourceRefID> {
225 for s in self.inputs.iter().rev() {
226 if let TokenSource::File(f, id) = s {
227 return SourceReference {
228 file: *id,
229 line: f.line(),
230 column: f.column(),
231 };
232 }
233 }
234 self.start_ref.last().copied().unwrap_or_default()
235 }
236 fn start_ref(&self) -> SourceReference<<ET::File as File>::SourceRefID> {
237 self.start_ref.last().copied().unwrap_or_default()
238 }
239 fn update_start_ref(&mut self) {
240 match self.inputs.last() {
241 Some(TokenSource::File(f, id)) => {
242 let rf = SourceReference {
243 file: *id,
244 line: f.line(),
245 column: f.column(),
246 };
247 match self.start_ref.last_mut() {
248 None => self.start_ref.push(rf),
249 Some(s) => *s = rf,
250 }
251 }
252 Some(TokenSource::Vec(v)) if v.is_empty() => {
253 if let Some(TokenSource::Vec(v)) = self.inputs.pop() {
254 self.vecs.push(v);
255 } else {
256 unreachable!()
257 }
258 self.update_start_ref();
259 }
260 _ => (),
261 }
262 }
263
264 fn get_args(&mut self) -> [Vec<ET::Token>; 9] {
265 match std::mem::take(&mut self.args) {
266 Some(a) => a,
267 None => unreachable!(), }
269 }
271
272 fn return_args(&mut self, mut exp: [Vec<ET::Token>; 9]) {
273 for a in &mut exp {
274 a.clear();
275 }
276 self.args = Some(exp);
277 }
278
279 fn endinput(
280 &mut self,
281 aux: &mut EngineAux<ET>,
282 state: &ET::State,
283 ) -> Result<(), InvalidCharacter<ET::Char>> {
284 for (i, s) in self.inputs.iter().enumerate().rev() {
285 if let TokenSource::File(f, _) = s {
286 aux.outputs.file_close(f.source.path().display());
287 let TokenSource::File(mut r, _) = self.inputs.remove(i) else {
288 unreachable!()
289 };
290 self.start_ref.pop();
291 if r.state != MouthState::NewLine {
292 let mut ret = Vec::new();
293 match r.read(
294 aux.memory.cs_interner_mut(),
295 state.get_catcode_scheme(),
296 state.get_endline_char(),
297 |t| ret.push(t),
298 ) {
299 Ok(_) => (),
300 Err(e) => e.recover(aux, state, self)?,
301 }
302 self.with_list(|ls| ls.extend(ret.into_iter().rev()));
303 }
304 return Ok(());
305 }
306 }
307 Ok(())
308 }
309
310 fn line_number(&self) -> usize {
311 for s in self.inputs.iter().rev() {
312 if let TokenSource::File(s, _) = s {
313 return s.line();
314 }
315 }
316 0
317 }
318
319 fn push_macro_exp(&mut self, mut exp: MacroExpansion<ET::Token>) {
320 self.with_list(|v| exp.consume_rev(v));
321 self.return_args(exp.args);
322 }
323
324 fn push_exp(&mut self, exp: &TokenList<ET::Token>) {
325 self.with_list(|v| v.extend(exp.0.iter().rev().cloned()));
326 }
327
328 fn push_vec(&mut self, exp: Vec<ET::Token>) {
329 self.with_list(|v| v.extend(exp.into_iter().rev()));
330 }
331 fn push_slice_rev(&mut self, exp: &[ET::Token]) {
332 self.with_list(|v| v.extend(exp.iter().cloned()));
333 }
334
335 fn push_string(&mut self, s: StringLineSource<ET::Char>) {
336 self.inputs
337 .push(TokenSource::String(InputTokenizer::new(s)));
338 }
339
340 fn requeue(&mut self, t: ET::Token) {
341 self.with_list(|v| v.push(t));
342 }
343
344 fn push_file(&mut self, f: ET::File) {
345 let id = f.sourceref();
347 let s = match f.line_source() {
348 Ok(s) => s,
349 Err(p) => panic!("File {} has no line source",p.display())
350 };
351 let rf = SourceReference {
352 file: id,
353 line: 0,
354 column: 0,
355 };
356 self.inputs
357 .push(TokenSource::File(InputTokenizer::new(s), id));
358 self.start_ref.push(rf);
359 }
360
361 fn get_next(
362 &mut self,
363 aux: &mut EngineAux<ET>,
364 state: &ET::State,
365 ) -> Result<Option<ET::Token>, InvalidCharacter<ET::Char>> {
366 while let Some(src) = self.inputs.last_mut() {
367 match src {
368 TokenSource::Vec(v) => match v.pop() {
369 Some(t) => return Ok(Some(t)),
370 _ => {
371 if let Some(TokenSource::Vec(v)) = self.inputs.pop() {
372 self.vecs.push(v);
373 }
374 }
375 },
376 TokenSource::String(s) => {
377 match s.get_next(
378 aux.memory.cs_interner_mut(),
379 state.get_catcode_scheme(),
380 state.get_endline_char(),
381 ) {
382 Ok(Some(t)) => return Ok(Some(t)),
383 Ok(None) => return Ok(Some(self.end_file(aux, state))),
384 Err(c) => {
385 c.recover::<_, InvalidCharacter<_>>(aux, state, self)?;
386 continue;
387 }
388 }
389 }
390 TokenSource::File(s, _) => {
391 let cc: &CategoryCodeScheme<ET::Char> = state.get_catcode_scheme();
392 let endline: Option<ET::Char> = state.get_endline_char();
393 match s.get_next(aux.memory.cs_interner_mut(), cc, endline) {
394 Ok(Some(t)) => return Ok(Some(t)),
395 Ok(None) => return Ok(Some(self.end_file(aux, state))),
396 Err(c) => {
397 c.recover::<_, InvalidCharacter<_>>(aux, state, self)?;
398 continue;
399 }
400 }
401 }
402 }
403 }
404 Ok(None)
405 }
406
407 fn iterate<R, E, F: FnMut(&mut EngineAux<ET>, ET::Token) -> TeXResult<Option<R>, ET>>(
408 &mut self,
409 aux: &mut EngineAux<ET>,
410 state: &ET::State,
411 mut cont: F,
412 eof: E,
413 ) -> TeXResult<R, ET>
414 where
415 E: Fn(&EngineAux<ET>, &ET::State, &mut Self) -> TeXResult<(), ET>,
416 {
417 'top: loop {
418 match self.inputs.last_mut() {
419 Some(TokenSource::Vec(v)) => {
420 while let Some(t) = v.pop() {
421 if let Some(r) = cont(aux, t)? {
422 return Ok(r);
423 }
424 }
425 if let Some(TokenSource::Vec(v)) = self.inputs.pop() {
426 self.vecs.push(v);
427 } else {
428 unreachable!()
429 }
430 }
431 Some(TokenSource::String(s)) => {
432 let cc = state.get_catcode_scheme();
433 let endline = state.get_endline_char();
434 loop {
435 match s.get_next(aux.memory.cs_interner_mut(), cc, endline) {
436 Ok(Some(t)) => {
437 if let Some(r) = cont(aux, t)? {
438 return Ok(r);
439 }
440 }
441 Err(c) => {
442 c.recover::<_, TeXError<_>>(aux, state, self)?;
443 continue 'top;
444 }
445 Ok(None) => {
446 eof(aux, state, self)?;
447 continue 'top;
448 }
449 }
450 }
451 }
452 Some(TokenSource::File(s, _)) => {
453 let cc = state.get_catcode_scheme();
454 let endline = state.get_endline_char();
455 loop {
456 match s.get_next(aux.memory.cs_interner_mut(), cc, endline) {
457 Ok(Some(t)) => {
458 if let Some(r) = cont(aux, t)? {
459 return Ok(r);
460 }
461 }
462 Err(c) => {
463 c.recover::<_, TeXError<_>>(aux, state, self)?;
464 continue 'top;
465 }
466 Ok(None) => {
467 eof(aux, state, self)?;
468 continue 'top;
469 }
470 }
471 }
472 }
473 None => eof(aux, state, self)?,
474 }
475 }
476 }
477
478 fn preview(
479 &self,
480 int: &<ET::CSName as CSName<ET::Char>>::Handler,
481 cc: &CategoryCodeScheme<ET::Char>,
482 esc: Option<ET::Char>,
483 ) -> String {
484 let mut str = String::new();
485 for src in self.inputs.iter().rev() {
486 match src {
487 TokenSource::String(s) => s.preview(&mut 1000, &mut str).unwrap(),
489 TokenSource::File(s, _) => {
491 s.preview(&mut 1000, &mut str).unwrap();
492 break;
493 }
494 TokenSource::Vec(v) => {
495 for t in v.iter().rev().take(1000) {
496 t.display_fmt(int, cc, esc, &mut str).unwrap()
497 }
498 } }
502 }
503 str
504 }
505}
506
507impl<ET: EngineTypes> DefaultMouth<ET> {
508 pub fn into<ET2: EngineTypes<Token = ET::Token, File = ET::File>>(self) -> DefaultMouth<ET2> {
510 DefaultMouth {
511 inputs: self.inputs,
512 args: self.args,
513 start_ref: self.start_ref,
514 vecs: self.vecs,
515 }
516 }
517 pub fn into_tokens<
519 ET2: EngineTypes<Char = ET::Char, File = ET::File>,
520 F: FnMut(ET::Token) -> ET2::Token,
521 >(
522 self,
523 mut token: F,
524 ) -> DefaultMouth<ET2> {
525 DefaultMouth {
526 inputs: self
527 .inputs
528 .into_iter()
529 .map(|s| match s {
530 TokenSource::String(s) => TokenSource::String(s),
531 TokenSource::File(s, id) => TokenSource::File(s, id),
532 TokenSource::Vec(v) => {
533 TokenSource::Vec(v.into_iter().map(&mut token).collect())
534 }
535 })
536 .collect(),
537 args: self.args.map(|[a0, a1, a2, a3, a4, a5, a6, a7, a8]| {
538 [
539 a0.into_iter().map(&mut token).collect(),
540 a1.into_iter().map(&mut token).collect(),
541 a2.into_iter().map(&mut token).collect(),
542 a3.into_iter().map(&mut token).collect(),
543 a4.into_iter().map(&mut token).collect(),
544 a5.into_iter().map(&mut token).collect(),
545 a6.into_iter().map(&mut token).collect(),
546 a7.into_iter().map(&mut token).collect(),
547 a8.into_iter().map(&mut token).collect(),
548 ]
549 }),
550 start_ref: self.start_ref,
551 vecs: self
552 .vecs
553 .into_iter()
554 .map(|v| v.into_iter().map(&mut token).collect())
555 .collect(),
556 }
557 }
558 fn with_list<Fn: FnOnce(&mut Vec<ET::Token>)>(&mut self, f: Fn) {
559 match self.inputs.last_mut() {
560 Some(TokenSource::Vec(v)) => f(v),
561 _ => {
562 let v = match self.vecs.pop() {
563 Some(mut v) => {
564 f(&mut v);
565 v
566 }
567 None => {
568 let mut v = Vec::new();
569 f(&mut v);
570 v
571 }
572 };
573 self.inputs.push(TokenSource::Vec(v));
574 }
575 };
576 }
577 fn end_file(&mut self, aux: &mut EngineAux<ET>, state: &ET::State) -> ET::Token {
578 match self.inputs.pop() {
579 Some(TokenSource::File(f, _)) => {
580 self.start_ref.pop();
581 aux.outputs.file_close(f.source.path().display());
582 }
583 Some(TokenSource::String(_)) => (), _ => unreachable!(),
585 };
586 let everyeof = state.get_primitive_tokens(PRIMITIVES.everyeof);
587 if everyeof.is_empty() {
588 ET::Token::eof()
589 } else {
590 self.requeue(ET::Token::eof());
591 self.push_exp(everyeof);
592 if let Some(TokenSource::Vec(v)) = self.inputs.last_mut() {
593 v.pop().unwrap()
594 } else {
595 unreachable!()
596 }
597 }
598 }
599}
600
601impl<ET: EngineTypes> EngineReferences<'_, ET> {
602 pub fn push_file(&mut self, f: ET::File) {
604 self.mouth.push_file(f);
605 }
606 pub fn push_every(&mut self, every: PrimitiveIdentifier) {
608 let tks = self.state.get_primitive_tokens(every);
609 self.mouth.push_exp(tks);
610 }
611 pub fn preview(&self) -> String {
613 self.mouth.preview(
614 self.aux.memory.cs_interner(),
615 self.state.get_catcode_scheme(),
616 self.state.get_escape_char(),
617 )
618 }
619}