simple/
simple.rs

1//a Imports
2use lexer_rs::PosnInCharStream;
3use lexer_rs::SimpleParseError;
4use lexer_rs::{CharStream, FmtContext, Lexer, LexerOfStr, LexerOfString, LexerParseResult};
5use lexer_rs::{LineColumn, StreamCharPos, StreamCharSpan};
6
7//a SimpleToken
8//tp SimpleToken
9#[derive(Debug, Clone, Copy)]
10pub enum SimpleToken<P, K>
11where
12    P: PosnInCharStream,
13    K: std::fmt::Debug + Copy + Clone + Sized,
14{
15    /// Comment is '//' and up to (and not including) a newline
16    CommentLine(StreamCharSpan<P>),
17    /// ID is an id start and any id following
18    Id(StreamCharSpan<P>),
19    /// digits is decimal digits
20    Digits(StreamCharSpan<P>),
21    /// OpenBra is one of ( [ {
22    OpenBra(P, char),
23    /// CloseBra is one of } ] )
24    CloseBra(P, char),
25    /// Whitespace is a span of spaces and tabs
26    Whitespace(StreamCharSpan<P>),
27    /// Keyword is one of the ascii keywords supplied
28    Keyword(P, K),
29    /// Newline is a Newline
30    Newline(P),
31    /// Char is an otherwise unknown char
32    Char(P, char),
33}
34
35//ip SimpleToken
36impl<P, K> SimpleToken<P, K>
37where
38    P: PosnInCharStream,
39    K: std::fmt::Debug + Copy + Clone + Sized,
40{
41    //fp parse_char
42    pub fn parse_char<L>(
43        stream: &L,
44        state: L::State,
45        ch: char,
46    ) -> LexerParseResult<P, Self, L::Error>
47    where
48        L: CharStream<P>,
49        L: Lexer<Token = Self, State = P>,
50    {
51        let pos = state;
52        match ch {
53            '\n' => Ok(Some((stream.consumed(state, 1), Self::Newline(pos)))),
54            '(' | '[' | '{' => Ok(Some((stream.consumed(state, 1), Self::OpenBra(pos, ch)))),
55            ')' | ']' | '}' => Ok(Some((stream.consumed(state, 1), Self::CloseBra(pos, ch)))),
56            ch => Ok(Some((stream.consumed_char(state, ch), Self::Char(pos, ch)))),
57        }
58    }
59
60    //fp parse_comment_line
61    pub fn parse_comment_line<L>(
62        stream: &L,
63        state: L::State,
64        ch: char,
65    ) -> LexerParseResult<P, Self, L::Error>
66    where
67        L: CharStream<P>,
68        L: Lexer<Token = Self, State = P>,
69    {
70        match stream.do_while(state, ch, &|n, ch| {
71            ((n < 2) && (ch == '/')) || ((n >= 2) && ch != '\n')
72        }) {
73            (state, Some((start, _n))) => {
74                let span = StreamCharSpan::new(start, state);
75                Ok(Some((state, SimpleToken::CommentLine(span))))
76            }
77            (_, None) => Ok(None),
78        }
79    }
80
81    //fp parse_digits
82    pub fn parse_digits<L>(
83        stream: &L,
84        state: L::State,
85        ch: char,
86    ) -> LexerParseResult<P, Self, L::Error>
87    where
88        L: CharStream<P>,
89        L: Lexer<Token = Self, State = P>,
90    {
91        match stream.do_while(state, ch, &|_, ch| ch.is_ascii_digit()) {
92            (state, Some((start, _n))) => {
93                let span = StreamCharSpan::new(start, state);
94                Ok(Some((state, SimpleToken::Digits(span))))
95            }
96            (_, None) => Ok(None),
97        }
98    }
99
100    //fp parse_whitespace
101    pub fn parse_whitespace<L>(
102        stream: &L,
103        state: L::State,
104        ch: char,
105    ) -> LexerParseResult<P, Self, L::Error>
106    where
107        L: CharStream<P>,
108        L: Lexer<Token = Self, State = P>,
109    {
110        match stream.do_while(state, ch, &|_, ch| (ch == ' ' || ch == '\t')) {
111            (state, Some((start, _))) => {
112                let span = StreamCharSpan::new(start, state);
113                Ok(Some((state, SimpleToken::Whitespace(span))))
114            }
115            (_, None) => Ok(None),
116        }
117    }
118
119    //fp parse_id
120    pub fn parse_id<L, F1, F2>(
121        stream: &L,
122        state: L::State,
123        ch: char,
124        is_id_start: F1,
125        is_id: F2,
126    ) -> LexerParseResult<P, Self, L::Error>
127    where
128        L: CharStream<P>,
129        L: Lexer<Token = Self, State = P>,
130        F1: Fn(char) -> bool,
131        F2: Fn(char) -> bool,
132    {
133        match stream.do_while(state, ch, &|n, ch| {
134            (n == 0 && is_id_start(ch)) || ((n > 0) && is_id(ch))
135        }) {
136            (state, Some((start, _))) => {
137                let span = StreamCharSpan::new(start, state);
138                Ok(Some((state, SimpleToken::Id(span))))
139            }
140            (_, None) => Ok(None),
141        }
142    }
143
144    //fp parse_keyword
145    pub fn parse_keyword<L>(
146        stream: &L,
147        state: L::State,
148        _ch: char,
149        keywords: &[(&[u8], K)],
150    ) -> LexerParseResult<P, Self, L::Error>
151    where
152        L: CharStream<P>,
153        L: Lexer<Token = Self, State = P>,
154    {
155        for (k, v) in keywords {
156            if stream.matches_bytes(&state, k) {
157                let n = k.len();
158                let next_state = stream.consumed(state, n);
159                return Ok(Some((next_state, SimpleToken::Keyword(state, *v))));
160            }
161        }
162        Ok(None)
163    }
164
165    //zz All done
166}
167
168//a Main
169type TextPos = StreamCharPos<LineColumn>;
170type LexToken = SimpleToken<TextPos, ()>;
171type LexError = SimpleParseError<TextPos>;
172type TextStream<'stream> = LexerOfStr<'stream, TextPos, LexToken, LexError>;
173
174type BoxDynLexTokenLexFn<'a> = Box<
175    dyn for<'call, 'stream> Fn(
176            &'call TextStream<'stream>,
177            TextPos,
178            char,
179        ) -> LexerParseResult<TextPos, LexToken, LexError>
180        + 'a,
181>;
182use std::env;
183#[derive(Default)]
184struct ParserVec<'a> {
185    pub parsers: Vec<BoxDynLexTokenLexFn<'a>>,
186}
187impl<'a> ParserVec<'a> {
188    pub fn new() -> Self {
189        let parsers = Vec::new();
190        Self { parsers }
191    }
192    pub fn add_parser<F>(&mut self, f: F)
193    where
194        F: Fn(&TextStream, TextPos, char) -> LexerParseResult<TextPos, LexToken, LexError>
195            + 'static,
196    {
197        self.parsers.push(Box::new(f));
198    }
199}
200
201fn main() -> Result<(), String> {
202    let args: Vec<String> = env::args().collect();
203    if args.len() < 2 {
204        return Err(format!("Usage: {} <expression>", args[0]));
205    }
206    let args_as_string = args[1..].join(" ");
207
208    let mut parsers = ParserVec::new();
209    parsers.add_parser(|a, b, c| LexToken::parse_whitespace(a, b, c));
210    parsers.add_parser(|a, b, c| LexToken::parse_comment_line(a, b, c));
211    parsers.add_parser(|a, b, c| LexToken::parse_digits(a, b, c));
212    parsers.add_parser(|a, b, c| LexToken::parse_char(a, b, c));
213
214    let l = LexerOfString::default().set_text(args_as_string);
215    let ts = l.lexer();
216    let tokens = ts.iter(&parsers.parsers);
217
218    println!("Parsing");
219    for t in tokens {
220        let t = {
221            match t {
222                Err(e) => {
223                    println!();
224                    let mut s = String::new();
225                    l.fmt_context(&mut s, &e.pos, &e.pos).unwrap();
226                    eprintln!("{}", s);
227                    return Err(format!("{}", e));
228                }
229                Ok(t) => t,
230            }
231        };
232        println!("{:?}", t);
233    }
234    println!();
235    println!("Text parsed okay");
236    Ok(())
237}