1#![allow(dead_code)]
18use std::{
19 fmt::{Debug, Write},
20 ops::RangeFrom,
21 sync::OnceLock,
22};
23
24use crosstabs::crosstabs_command;
25use ctables::ctables_command;
26use data_list::data_list_command;
27use descriptives::descriptives_command;
28use either::Either;
29use enumset::{EnumSet, EnumSetType};
30use pspp_derive::FromTokens;
31
32use crate::{
33 format::AbstractFormat,
34 identifier::Identifier,
35 integer::ToInteger,
36 lex::{
37 Punct, Token,
38 command_name::CommandMatcher,
39 lexer::{LexToken, TokenSlice},
40 },
41 message::{Diagnostic, Diagnostics},
42};
43
44pub mod crosstabs;
45pub mod ctables;
46pub mod data_list;
47pub mod descriptives;
48
49#[derive(Debug, EnumSetType)]
50enum State {
51 Initial,
53
54 Data,
56
57 InputProgram,
59
60 FileType,
62
63 NestedData,
65
66 NestedInputProgram,
68}
69
70struct Command {
71 allowed_states: EnumSet<State>,
72 enhanced_only: bool,
73 testing_only: bool,
74 no_abbrev: bool,
75 name: &'static str,
76 run: Box<dyn Fn(&mut Context) + Send + Sync>, }
78
79#[derive(Debug)]
80enum ParseError {
81 Error(Diagnostics),
82 Mismatch(Diagnostics),
83}
84
85#[derive(Debug)]
86struct Parsed<T> {
87 value: T,
88 rest: TokenSlice,
89 diagnostics: Diagnostics,
90}
91
92impl<T> Parsed<T> {
93 pub fn new(value: T, rest: TokenSlice, warnings: Diagnostics) -> Self {
94 Self {
95 value,
96 rest,
97 diagnostics: warnings,
98 }
99 }
100 pub fn ok(value: T, rest: TokenSlice) -> Self {
101 Self {
102 value,
103 rest,
104 diagnostics: Diagnostics::default(),
105 }
106 }
107 pub fn into_tuple(self) -> (T, TokenSlice, Diagnostics) {
108 (self.value, self.rest, self.diagnostics)
109 }
110 pub fn take_diagnostics(self, d: &mut Diagnostics) -> (T, TokenSlice) {
111 let (value, rest, mut diagnostics) = self.into_tuple();
112 d.0.append(&mut diagnostics.0);
113 (value, rest)
114 }
115 pub fn map<F, R>(self, f: F) -> Parsed<R>
116 where
117 F: FnOnce(T) -> R,
118 {
119 Parsed {
120 value: f(self.value),
121 rest: self.rest,
122 diagnostics: self.diagnostics,
123 }
124 }
125 pub fn warn(self, mut warnings: Diagnostics) -> Self {
126 Self {
127 value: self.value,
128 rest: self.rest,
129 diagnostics: {
130 let mut vec = self.diagnostics.0;
131 vec.append(&mut warnings.0);
132 Diagnostics(vec)
133 },
134 }
135 }
136}
137
138type ParseResult<T> = Result<Parsed<T>, ParseError>;
139
140trait MismatchToError {
141 fn mismatch_to_error(self) -> Self;
142}
143
144impl<T> MismatchToError for ParseResult<T> {
145 fn mismatch_to_error(self) -> Self {
146 match self {
147 Err(ParseError::Mismatch(diagnostic)) => Err(ParseError::Error(diagnostic)),
148 rest => rest,
149 }
150 }
151}
152
153trait FromTokens {
154 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
155 where
156 Self: Sized;
157}
158
159impl<T> FromTokens for Option<T>
160where
161 T: FromTokens,
162{
163 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
164 where
165 Self: Sized,
166 {
167 match T::from_tokens(input) {
168 Ok(p) => Ok(p.map(Some)),
169 Err(ParseError::Mismatch(_)) => Ok(Parsed::ok(None, input.clone())),
170 Err(ParseError::Error(error)) => Err(ParseError::Error(error)),
171 }
172 }
173}
174
175impl<L, R> FromTokens for Either<L, R>
176where
177 L: FromTokens,
178 R: FromTokens,
179{
180 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
181 where
182 Self: Sized,
183 {
184 match L::from_tokens(input) {
185 Ok(p) => Ok(p.map(Either::Left)),
186 Err(ParseError::Mismatch(_)) => Ok(R::from_tokens(input)?.map(Either::Right)),
187 Err(ParseError::Error(error)) => Err(ParseError::Error(error)),
188 }
189 }
190}
191
192impl<A, B> FromTokens for (A, B)
193where
194 A: FromTokens,
195 B: FromTokens,
196{
197 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
198 where
199 Self: Sized,
200 {
201 let (a, input, mut diagnostics) = A::from_tokens(input)?.into_tuple();
202 let (b, rest, mut diagnostics2) = B::from_tokens(&input)?.into_tuple();
203 diagnostics.0.append(&mut diagnostics2.0);
204 Ok(Parsed::new((a, b), rest, diagnostics))
205 }
206}
207
208impl<A, B, C> FromTokens for (A, B, C)
209where
210 A: FromTokens,
211 B: FromTokens,
212 C: FromTokens,
213{
214 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
215 where
216 Self: Sized,
217 {
218 let (a, input, mut diagnostics) = A::from_tokens(input)?.into_tuple();
219 let (b, input, mut diagnostics2) = B::from_tokens(&input)?.into_tuple();
220 let (c, rest, mut diagnostics3) = C::from_tokens(&input)?.into_tuple();
221 diagnostics.0.append(&mut diagnostics2.0);
222 diagnostics.0.append(&mut diagnostics3.0);
223 Ok(Parsed::new((a, b, c), rest, diagnostics))
224 }
225}
226
227#[derive(Debug, pspp_derive::FromTokens)]
228#[pspp(syntax = "/")]
229pub struct Slash;
230
231#[derive(Debug)]
232pub struct Comma;
233
234impl FromTokens for Comma {
235 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
236 where
237 Self: Sized,
238 {
239 _parse_token(input, &Token::Punct(Punct::Comma)).map(|p| p.map(|_| Comma))
240 }
241}
242
243#[derive(Debug, pspp_derive::FromTokens)]
244#[pspp(syntax = "=")]
245pub struct Equals;
246
247#[derive(Debug, pspp_derive::FromTokens)]
248#[pspp(syntax = "&")]
249pub struct And;
250
251#[derive(Debug, pspp_derive::FromTokens)]
252#[pspp(syntax = ">")]
253pub struct Gt;
254
255#[derive(Debug, pspp_derive::FromTokens)]
256#[pspp(syntax = "+")]
257pub struct Plus;
258
259#[derive(Debug, pspp_derive::FromTokens)]
260#[pspp(syntax = "-")]
261pub struct Dash;
262
263#[derive(Debug, pspp_derive::FromTokens)]
264#[pspp(syntax = "*")]
265pub struct Asterisk;
266
267#[derive(Debug, pspp_derive::FromTokens)]
268#[pspp(syntax = "**")]
269pub struct Exp;
270
271#[derive(Debug, pspp_derive::FromTokens)]
272struct By;
273
274pub struct Punctuated<T, P = Option<Comma>> {
275 head: Vec<(T, P)>,
276 tail: Option<T>,
277}
278
279impl<T, P> Debug for Punctuated<T, P>
280where
281 T: Debug,
282{
283 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
284 write!(f, "[")?;
285 for (index, item) in self
286 .head
287 .iter()
288 .map(|(t, _p)| t)
289 .chain(self.tail.iter())
290 .enumerate()
291 {
292 if index > 0 {
293 write!(f, ", ")?;
294 }
295 write!(f, "{item:?}")?;
296 }
297 write!(f, "]")
298 }
299}
300
301impl<T, P> FromTokens for Punctuated<T, P>
302where
303 T: FromTokens,
304 P: FromTokens,
305{
306 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
307 where
308 Self: Sized,
309 {
310 let mut head = Vec::new();
311 let mut warnings_vec = Vec::new();
312 let mut input = input.clone();
313 let tail = loop {
314 let t = match T::from_tokens(&input) {
315 Ok(Parsed {
316 value,
317 rest,
318 diagnostics: mut warnings,
319 }) => {
320 warnings_vec.append(&mut warnings.0);
321 input = rest;
322 value
323 }
324 Err(ParseError::Mismatch(_)) => break None,
325 Err(ParseError::Error(e)) => return Err(ParseError::Error(e)),
326 };
327 let p = match P::from_tokens(&input) {
328 Ok(Parsed {
329 value,
330 rest,
331 diagnostics: mut warnings,
332 }) => {
333 warnings_vec.append(&mut warnings.0);
334 input = rest;
335 value
336 }
337 Err(ParseError::Mismatch(_)) => break Some(t),
338 Err(ParseError::Error(e)) => return Err(ParseError::Error(e)),
339 };
340 head.push((t, p));
341 };
342 Ok(Parsed {
343 value: Punctuated { head, tail },
344 rest: input,
345 diagnostics: Diagnostics(warnings_vec),
346 })
347 }
348}
349
350impl<T> FromTokens for Box<T>
351where
352 T: FromTokens,
353{
354 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
355 where
356 Self: Sized,
357 {
358 T::from_tokens(input).map(|p| p.map(|value| Box::new(value)))
359 }
360}
361
362pub struct Subcommands<T>(Vec<T>);
363
364impl<T> Debug for Subcommands<T>
365where
366 T: Debug,
367{
368 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369 write!(f, "Subcommands[")?;
370 for (index, item) in self.0.iter().enumerate() {
371 if index > 0 {
372 writeln!(f, ",")?;
373 }
374 write!(f, "{item:?}")?;
375 }
376 write!(f, "]")
377 }
378}
379
380impl<T> FromTokens for Subcommands<T>
381where
382 T: FromTokens,
383{
384 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
385 where
386 Self: Sized,
387 {
388 let mut items = Vec::new();
389 let mut diagnostics = Vec::new();
390 let mut input = input.clone();
391 loop {
392 let start = input.skip_until(|token| token != &Token::Punct(Punct::Slash));
393 if start.is_empty() {
394 break;
395 }
396 let end = start.skip_to(&Token::Punct(Punct::Slash));
397 let subcommand = start.subslice(0..start.len() - end.len());
398 match T::from_tokens(&subcommand) {
399 Ok(p) => {
400 let (value, rest, mut d) = p.into_tuple();
401 items.push(value);
402 diagnostics.append(&mut d.0);
403 if !rest.is_empty() {
404 diagnostics.push(rest.warning("Syntax error expecting end of subcommand."));
405 }
406 }
407 Err(ParseError::Error(mut d) | ParseError::Mismatch(mut d)) => {
408 diagnostics.append(&mut d.0);
409 }
410 }
411 input = end;
412 }
413 println!("{diagnostics:?}");
414 Ok(Parsed {
415 value: Subcommands(items),
416 rest: input,
417 diagnostics: Diagnostics(diagnostics),
418 })
419 }
420}
421
422#[derive(Debug)]
423pub struct Seq0<T>(Vec<T>);
424
425impl<T> FromTokens for Seq0<T>
426where
427 T: FromTokens,
428{
429 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
430 where
431 Self: Sized,
432 {
433 let mut values_vec = Vec::new();
434 let mut warnings_vec = Vec::new();
435 let mut input = input.clone();
436 while !input.is_empty() {
437 match T::from_tokens(&input) {
438 Ok(Parsed {
439 value,
440 rest,
441 diagnostics: mut warnings,
442 }) => {
443 warnings_vec.append(&mut warnings.0);
444 if input.len() == rest.len() {
445 break;
446 }
447 values_vec.push(value);
448 input = rest;
449 }
450 Err(ParseError::Mismatch(_)) => break,
451 Err(ParseError::Error(e)) => return Err(ParseError::Error(e)),
452 }
453 }
454 Ok(Parsed {
455 value: Seq0(values_vec),
456 rest: input,
457 diagnostics: Diagnostics(warnings_vec),
458 })
459 }
460}
461
462#[derive(Debug)]
463pub struct Seq1<T>(Vec<T>);
464
465impl<T> FromTokens for Seq1<T>
466where
467 T: FromTokens,
468{
469 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
470 where
471 Self: Sized,
472 {
473 let mut values_vec = Vec::new();
474 let mut warnings_vec = Vec::new();
475 let mut input = input.clone();
476 while !input.is_empty() {
477 match T::from_tokens(&input) {
478 Ok(Parsed {
479 value,
480 rest,
481 diagnostics: mut warnings,
482 }) => {
483 warnings_vec.append(&mut warnings.0);
484 if input.len() == rest.len() {
485 break;
486 }
487 values_vec.push(value);
488 input = rest;
489 }
490 Err(ParseError::Mismatch(_)) => break,
491 Err(ParseError::Error(e)) => return Err(ParseError::Error(e)),
492 }
493 }
494 if values_vec.is_empty() {
495 return Err(ParseError::Mismatch(input.error("Syntax error.").into()));
496 }
497 Ok(Parsed {
498 value: Seq1(values_vec),
499 rest: input,
500 diagnostics: Diagnostics(warnings_vec),
501 })
502 }
503}
504
505impl FromTokens for TokenSlice {
540 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
541 where
542 Self: Sized,
543 {
544 Ok(Parsed::ok(input.clone(), input.end()))
545 }
546}
547
548#[derive(Debug)]
549struct Subcommand<T>(pub T);
550
551impl<T> FromTokens for Subcommand<T>
552where
553 T: FromTokens,
554{
555 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
556 where
557 Self: Sized,
558 {
559 let start = input.skip_until(|token| token != &Token::Punct(Punct::Slash));
560 if start.is_empty() {
561 return Err(ParseError::Error(
562 input.error("Syntax error at end of input.").into(),
563 ));
564 }
565 let end = start.skip_to(&Token::Punct(Punct::Slash));
566 let subcommand = start.subslice(0..start.len() - end.len());
567 let (value, rest, mut warnings) = T::from_tokens(&subcommand)?.into_tuple();
568 if !rest.is_empty() {
569 warnings
570 .0
571 .push(rest.warning("Syntax error expecting end of subcommand."));
572 }
573 Ok(Parsed::new(Self(value), end, warnings))
574 }
575}
576
577#[derive(Debug)]
578struct InParens<T>(pub T);
579
580impl<T> FromTokens for InParens<T>
581where
582 T: FromTokens,
583{
584 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
585 where
586 Self: Sized,
587 {
588 let ((), rest, _) = parse_token(input, &Token::Punct(Punct::LParen))?.into_tuple();
589 let (value, rest, warnings) = T::from_tokens(&rest)?.into_tuple();
590 let ((), rest, _) = parse_token(&rest, &Token::Punct(Punct::RParen))?.into_tuple();
591 Ok(Parsed {
592 value: Self(value),
593 rest,
594 diagnostics: warnings,
595 })
596 }
597}
598
599#[derive(Debug)]
600struct InSquares<T>(pub T);
601
602impl<T> FromTokens for InSquares<T>
603where
604 T: FromTokens,
605{
606 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
607 where
608 Self: Sized,
609 {
610 let ((), rest, _) = parse_token(input, &Token::Punct(Punct::LSquare))?.into_tuple();
611 let (value, rest, warnings) = T::from_tokens(&rest)?.into_tuple();
612 let ((), rest, _) = parse_token(&rest, &Token::Punct(Punct::RSquare))?.into_tuple();
613 Ok(Parsed {
614 value: Self(value),
615 rest,
616 diagnostics: warnings,
617 })
618 }
619}
620
621fn parse_token_if<F, R>(input: &TokenSlice, parse: F) -> ParseResult<R>
622where
623 F: Fn(&Token) -> Option<R>,
624{
625 if let Some(token) = input.get_token(0) {
626 if let Some(result) = parse(token) {
627 return Ok(Parsed::ok(result, input.subslice(1..input.len())));
628 }
629 }
630 Err(ParseError::Mismatch(Diagnostics::default()))
631}
632
633fn _parse_token(input: &TokenSlice, token: &Token) -> ParseResult<Token> {
634 if let Some(rest) = input.skip(token) {
635 Ok(Parsed::ok(input.first().token.clone(), rest))
636 } else {
637 Err(ParseError::Mismatch(
638 input.error(format!("expecting {token}")).into(),
639 ))
640 }
641}
642
643fn parse_token(input: &TokenSlice, token: &Token) -> ParseResult<()> {
644 if let Some(rest) = input.skip(token) {
645 Ok(Parsed::ok((), rest))
646 } else {
647 Err(ParseError::Mismatch(
648 input.error(format!("expecting {token}")).into(),
649 ))
650 }
651}
652
653fn parse_syntax(input: &TokenSlice, syntax: &str) -> ParseResult<()> {
654 if let Some(rest) = input.skip_syntax(syntax) {
655 Ok(Parsed::ok((), rest))
656 } else {
657 Err(ParseError::Mismatch(
658 input.error(format!("expecting {syntax}")).into(),
659 ))
660 }
661}
662
663pub type VarList = Punctuated<VarRange>;
664
665pub struct Number(f64);
666
667impl Debug for Number {
668 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
669 write!(f, "{:?}", self.0)
670 }
671}
672
673impl FromTokens for Number {
674 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
675 where
676 Self: Sized,
677 {
678 parse_token_if(input, |token| token.as_number().map(Number))
679 .map_err(|_| ParseError::Mismatch(input.error(String::from("expecting number")).into()))
680 }
681}
682
683#[derive(Debug)]
684pub struct Integer(i64);
685
686impl FromTokens for Integer {
687 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
688 where
689 Self: Sized,
690 {
691 parse_token_if(input, |token| token.as_integer().map(Integer)).map_err(|_| {
692 ParseError::Mismatch(input.error(String::from("expecting integer")).into())
693 })
694 }
695}
696
697pub enum VarRange {
698 Single(Identifier),
699 Range(Identifier, Identifier),
700 All,
701}
702
703impl Debug for VarRange {
704 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
705 match self {
706 Self::Single(var) => write!(f, "{var:?}"),
707 Self::Range(from, to) => write!(f, "{from:?} TO {to:?}"),
708 Self::All => write!(f, "ALL"),
709 }
710 }
711}
712
713impl FromTokens for VarRange {
714 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
715 where
716 Self: Sized,
717 {
718 if let Ok(Parsed { rest, .. }) = parse_token(input, &Token::Punct(Punct::All)) {
719 Ok(Parsed::ok(Self::All, rest))
720 } else {
721 let (from, rest, _) = parse_id(input)?.into_tuple();
722 if let Ok(Parsed { rest, .. }) = parse_token(&rest, &Token::Punct(Punct::To)) {
723 if let Ok(p) = parse_id(&rest) {
724 return Ok(p.map(|to| Self::Range(from, to)));
725 }
726 }
727 Ok(Parsed::ok(Self::Single(from), rest))
728 }
729 }
730}
731
732fn parse_id(input: &TokenSlice) -> ParseResult<Identifier> {
733 let mut iter = input.iter();
734 if let Some(LexToken {
735 token: Token::Id(id),
736 ..
737 }) = iter.next()
738 {
739 Ok(Parsed::ok(id.clone(), iter.remainder()))
740 } else {
741 Err(ParseError::Mismatch(
742 input.error("Syntax error expecting identifier.").into(),
743 ))
744 }
745}
746
747fn parse_format(input: &TokenSlice) -> ParseResult<AbstractFormat> {
748 let mut iter = input.iter();
749 if let Some(LexToken {
750 token: Token::Id(id),
751 ..
752 }) = iter.next()
753 {
754 if let Ok(format) = id.0.as_ref().parse() {
755 return Ok(Parsed::ok(format, iter.remainder()));
756 }
757 }
758 Err(ParseError::Mismatch(
759 input.error("Syntax error expecting identifier.").into(),
760 ))
761}
762
763fn parse_string(input: &TokenSlice) -> ParseResult<String> {
764 let mut iter = input.iter();
765 if let Some(LexToken {
766 token: Token::String(s),
767 ..
768 }) = iter.next()
769 {
770 Ok(Parsed::ok(s.clone(), iter.remainder()))
771 } else {
772 Err(ParseError::Mismatch(
773 input.error("Syntax error expecting identifier.").into(),
774 ))
775 }
776}
777
778impl FromTokens for Identifier {
779 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
780 where
781 Self: Sized,
782 {
783 parse_id(input)
784 }
785}
786
787impl FromTokens for String {
788 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
789 where
790 Self: Sized,
791 {
792 parse_string(input)
793 }
794}
795
796impl FromTokens for AbstractFormat {
797 fn from_tokens(input: &TokenSlice) -> ParseResult<Self>
798 where
799 Self: Sized,
800 {
801 parse_format(input)
802 }
803}
804
805fn collect_subcommands(src: TokenSlice) -> Vec<TokenSlice> {
806 src.split(|token| token.token == Token::Punct(Punct::Slash))
807 .filter(|slice| !slice.is_empty())
808 .collect()
809}
810
811fn commands() -> &'static [Command] {
812 fn new_commands() -> Vec<Command> {
813 vec![
814 descriptives_command(),
815 crosstabs_command(),
816 ctables_command(),
817 data_list_command(),
818 Command {
819 allowed_states: EnumSet::all(),
820 enhanced_only: false,
821 testing_only: false,
822 no_abbrev: false,
823 name: "ECHO",
824 run: Box::new(|_context| todo!()),
825 },
826 ]
827 }
828
829 static COMMANDS: OnceLock<Vec<Command>> = OnceLock::new();
830 COMMANDS.get_or_init(new_commands).as_slice()
831}
832
833fn parse_command_word(lexer: &mut TokenSlice, s: &mut String, n: usize) -> bool {
834 let separator = match s.chars().next_back() {
835 Some(c) if c != '-' => " ",
836 _ => "",
837 };
838
839 match lexer.get_token(n) {
840 Some(Token::Punct(Punct::Dash)) => {
841 s.push('-');
842 true
843 }
844 Some(Token::Id(id)) => {
845 write!(s, "{separator}{id}").unwrap();
846 true
847 }
848 Some(Token::Number(number)) if number.is_sign_positive() => {
849 if let Some(integer) = number.to_exact_usize() {
850 write!(s, "{separator}{integer}").unwrap();
851 true
852 } else {
853 false
854 }
855 }
856 _ => false,
857 }
858}
859
860fn find_best_match(s: &str) -> (Option<&'static Command>, isize) {
861 let mut cm = CommandMatcher::new(s);
862 for command in commands() {
863 cm.add(command.name, command);
864 }
865 cm.get_match()
866}
867
868fn parse_command_name(
869 lexer: &mut TokenSlice,
870 error: &dyn Fn(Diagnostic),
871) -> Result<(&'static Command, usize), ()> {
872 let mut s = String::new();
873 let mut word = 0;
874 let mut missing_words = 0;
875 let mut command = None;
876 while parse_command_word(lexer, &mut s, word) {
877 (command, missing_words) = find_best_match(&s);
878 if missing_words <= 0 {
879 break;
880 }
881 word += 1;
882 }
883 if command.is_none() && missing_words > 0 {
884 s.push_str(" .");
885 (command, missing_words) = find_best_match(&s);
886 s.truncate(s.len() - 2);
887 }
888
889 match command {
890 Some(command) => Ok((command, ((word as isize + 1) + missing_words) as usize)),
891 None => {
892 if word == 0 {
893 error(
894 lexer
895 .subslice(0..1)
896 .error("Syntax error expecting command name"),
897 )
898 } else {
899 error(lexer.subslice(0..word + 1).error("Unknown command `{s}`."))
900 };
901 Err(())
902 }
903 }
904}
905
906pub enum Success {
907 Success,
908 Eof,
909 Finish,
910}
911
912pub fn end_of_command(context: &Context, range: RangeFrom<usize>) -> Result<Success, ()> {
913 match context.lexer.get_token(range.start) {
914 None | Some(Token::End) => Ok(Success::Success),
915 _ => {
916 context.error(
917 context
918 .lexer
919 .subslice(range.start..context.lexer.len())
920 .error("Syntax error expecting end of command."),
921 );
922 Err(())
923 }
924 }
925}
926
927fn parse_in_state(mut lexer: TokenSlice, error: &dyn Fn(Diagnostic), _state: State) {
928 match lexer.get_token(0) {
929 None | Some(Token::End) => (),
930 _ => match parse_command_name(&mut lexer, error) {
931 Ok((command, n_tokens)) => {
932 let mut context = Context {
933 error,
934 lexer: lexer.subslice(n_tokens..lexer.len()),
935 command_name: Some(command.name),
936 };
937 (command.run)(&mut context);
938 }
939 Err(error) => println!("{error:?}"),
940 },
941 }
942}
943
944pub fn parse_command(lexer: TokenSlice, error: &dyn Fn(Diagnostic)) {
945 parse_in_state(lexer, error, State::Initial)
946}
947
948pub struct Context<'a> {
949 error: &'a dyn Fn(Diagnostic),
950 lexer: TokenSlice,
951 command_name: Option<&'static str>,
952}
953
954impl Context<'_> {
955 pub fn error(&self, diagnostic: Diagnostic) {
956 (self.error)(diagnostic);
957 }
958}