1use crate::lexer;
2use crate::ast;
3
4use crate::lexer::TokenVariant;
5
6pub fn eat_absnumber<'a>(input: &'a str)
12 -> Result<(ast::AbsNumber<'a>, &'a str), (String, &'a str)>
13{
14 let cursor0 = input;
15 let (token0, cursor1) = lexer::eat(cursor0)?;
16 match token0.variant
17 {
18 TokenVariant::Number(val) =>
19 {
20 let numbertok = ast::NumberToken { tok: token0.tok, val };
21 Ok((ast::AbsNumber { alt: Box::new(numbertok) }, cursor1))
22 }
23 TokenVariant::N =>
24 {
25 let keywordtok = ast::NToken { tok: token0.tok };
26 let (token1, cursor2) = lexer::eat(cursor1)?;
27 if let TokenVariant::LeftParens = token1.variant {} else
28 {
29 return Err((String::from("Expected `(`"), token1.tok));
30 }
31 let lparenstok = ast::LeftParensToken { tok: token1.tok };
32 let (number, cursor3) = eat_number(cursor2)?;
33 let (token3, cursor4) = lexer::eat(cursor3)?;
34 if let TokenVariant::RightParens = token3.variant {} else
35 {
36 return Err((String::from("Expected `)`"), token3.tok));
37 }
38 let rparenstok = ast::RightParensToken { tok: token3.tok };
39 let n = ast::N::new(keywordtok, lparenstok, number, rparenstok);
40 Ok((ast::AbsNumber { alt: Box::new(n) }, cursor4))
41 }
42 TokenVariant::Read =>
43 {
44 let keywordtok = ast::ReadToken { tok: token0.tok };
45 let (token1, cursor2) = lexer::eat(cursor1)?;
46 if let TokenVariant::LeftParens = token1.variant {} else
47 {
48 return Err((String::from("Expected `(`"), token1.tok));
49 }
50 let lparenstok = ast::LeftParensToken { tok: token1.tok };
51 let (token2, cursor3) = lexer::eat(cursor2)?;
52 if let TokenVariant::RightParens = token2.variant {} else
53 {
54 return Err((String::from("Expected `)`"), token2.tok));
55 }
56 let rparenstok = ast::RightParensToken { tok: token2.tok };
57 let read = ast::Read::new(keywordtok, lparenstok, rparenstok);
58 Ok((ast::AbsNumber { alt: Box::new(read) }, cursor3))
59 }
60 _ => Err((String::from("Expected number"), token0.tok))
61 }
62}
63
64pub fn eat_number<'a>(input: &'a str)
65 -> Result<(ast::Number<'a>, &'a str), (String, &'a str)>
66{
67 let cursor0 = input;
68 let (token0, cursor1) = lexer::eat(cursor0)?;
69 let cursorlast; let number1 : ast::Number = match token0.variant
71 {
72 TokenVariant::Number(_) | TokenVariant::N | TokenVariant::Read =>
73 {
74 let (absnum, cursor1) = eat_absnumber(cursor0)?;
75 let absolutenumber = ast::AbsoluteNumber::new(absnum);
76 cursorlast = cursor1;
77 ast::Number { alt: Box::new(absolutenumber) }
78 }
79 TokenVariant::Plus | TokenVariant::Minus =>
80 {
81 let unmathop = ast::UnMathOp { alt: match token0.variant
82 {
83 TokenVariant::Plus =>
84 Box::new(ast::PlusToken { tok: token0.tok }),
85 TokenVariant::Minus =>
86 Box::new(ast::MinusToken { tok: token0.tok }),
87 _ => unreachable!()
88 }
89 };
90 let (number, cursor2) = eat_number(cursor1)?;
91 let unopnum = ast::UnOpNumber::new(unmathop, number);
92 cursorlast = cursor2;
93 ast::Number { alt: Box::new(unopnum) }
94 }
95 TokenVariant::LeftParens =>
96 {
97 let lparenstok = ast::LeftParensToken { tok: token0.tok };
98 let (number, cursor2) = eat_number(cursor1)?;
99 let (token2, cursor3) = lexer::eat(cursor2)?;
100 if let TokenVariant::RightParens = token2.variant {} else
101 {
102 return Err((String::from("Expected `)`"), token2.tok));
103 }
104 let rparenstok = ast::RightParensToken { tok: token2.tok };
105 let parensnum = ast::ParensNumber::new(lparenstok,
106 number,
107 rparenstok);
108 cursorlast = cursor3;
109 ast::Number { alt: Box::new(parensnum) }
110 }
111 TokenVariant::String | TokenVariant::U =>
112 {
113 let (string, cursor1) = eat_string(cursor0)?;
114 let stringtonum = ast::StringToNum { string };
115 cursorlast = cursor1;
116 ast::Number { alt: Box::new(stringtonum) }
117 }
118 _ => { return Err((String::from("Expected number"), token0.tok)); }
119 };
120
121 let (tokenlast, cursorlastplus1) = lexer::eat(cursorlast)?;
122 match tokenlast.variant
123 {
124 TokenVariant::Plus | TokenVariant::Minus | TokenVariant::MathOp =>
125 {
126 let binmathop = ast::BinMathOp { alt : match tokenlast.variant
127 {
128 TokenVariant::Plus =>
129 Box::new(ast::PlusToken { tok: tokenlast.tok }),
130 TokenVariant::Minus =>
131 Box::new(ast::MinusToken { tok: tokenlast.tok }),
132 TokenVariant::MathOp =>
133 Box::new(ast::MathOpToken { tok: tokenlast.tok }),
134 _ => unreachable!()
135 }
136 };
137 let (number2, cursorlastplus2) = eat_number(cursorlastplus1)?;
138 let binopnum = ast::BinOpNumber::new(number1, binmathop, number2);
139 Ok((ast::Number { alt: Box::new(binopnum) }, cursorlastplus2))
140 }
141 _ => Ok((number1, cursorlast))
142 }
143}
144
145pub fn eat_boolean<'a>(input: &'a str)
146 -> Result<(ast::Boolean<'a>, &'a str), (String, &'a str)>
147{
148 let cursor0 = input;
149 let (token0, cursor1) = lexer::eat(cursor0)?;
150 let cursorlast; let boolean1 : ast::Boolean = match token0.variant
152 {
153 TokenVariant::UnBoolOp =>
154 {
155 let unbooloptok = ast::UnBoolOpToken { tok: token0.tok };
156 let (boolean, cursor2) = eat_boolean(cursor1)?;
157 let unopboolean = ast::UnOpBoolean::new(unbooloptok, boolean);
158 cursorlast = cursor2;
159 ast::Boolean { alt: Box::new(unopboolean) }
160 }
161 TokenVariant::LeftParens =>
162 {
163 let lparenstok = ast::LeftParensToken { tok: token0.tok };
164 let (boolean, cursor2) = eat_boolean(cursor1)?;
165 let (token2, cursor3) = lexer::eat(cursor2)?;
166 if let TokenVariant::RightParens = token2.variant {} else
167 {
168 return Err((String::from("Expected `)`"), token2.tok));
169 }
170 let rparenstok = ast::RightParensToken { tok: token2.tok };
171 let parensbool = ast::ParensBoolean::new(lparenstok,
172 boolean,
173 rparenstok);
174 cursorlast = cursor3;
175 ast::Boolean { alt: Box::new(parensbool) }
176 }
177 TokenVariant::Number(_) | TokenVariant::N | TokenVariant::Read
178 | TokenVariant::Plus | TokenVariant::Minus
179 | TokenVariant::String | TokenVariant::U =>
180 {
181 let (number1, cursor1) = eat_number(cursor0)?;
182 let (token1, cursor2) = lexer::eat(cursor1)?;
183 match token1.variant
184 {
185 TokenVariant::BinNumBoolOp =>
186 {
187 let binnumbooloptok = ast::BinNumBoolOpToken {
190 tok: token1.tok };
191 let (number2, cursor3) = eat_number(cursor2)?;
192 let binopnumboolean =
193 ast::BinOpNumBoolean::new(number1,
194 binnumbooloptok,
195 number2);
196 cursorlast = cursor3;
197 ast::Boolean { alt: Box::new(binopnumboolean) }
198 }
199 _ =>
200 {
201 let numtobool = ast::NumToBool { num: number1 };
204 cursorlast = cursor1;
205 ast::Boolean { alt: Box::new(numtobool) }
206 }
207 }
208 }
209 _ => { return Err((String::from("Expected boolean"), token0.tok)); }
210 };
211
212 let (tokenlast, cursorlastplus1) = lexer::eat(cursorlast)?;
213 match tokenlast.variant
214 {
215 TokenVariant::BinBoolOp =>
216 {
217 let binbooloptok = ast::BinBoolOpToken { tok: tokenlast.tok };
218 let (boolean2, cursorlastplus2) = eat_boolean(cursorlastplus1)?;
219 let binopboolean = ast::BinOpBoolean::new(boolean1,
220 binbooloptok,
221 boolean2);
222 Ok((ast::Boolean { alt: Box::new(binopboolean) }, cursorlastplus2))
223 }
224 _ => Ok((boolean1, cursorlast))
225 }
226}
227
228pub fn eat_string<'a>(input: &'a str)
229 -> Result<(ast::String_<'a>, &'a str), (String, &'a str)>
230{
231 let cursor0 = input;
232 let (token0, cursor1) = lexer::eat(cursor0)?;
233 let cursorlast; let string1 : ast::String_<'a> = match token0.variant
235 {
236 TokenVariant::String =>
237 {
238 let stringtoken = ast::StringToken { tok: token0.tok };
239 cursorlast = cursor1;
240 ast::String_ { alt: Box::new(stringtoken) }
241 }
242 TokenVariant::U =>
243 {
244 let keywordtok = ast::UToken { tok: token0.tok };
245 let (token1, cursor2) = lexer::eat(cursor1)?;
246 if let TokenVariant::LeftParens = token1.variant {} else
247 {
248 return Err((String::from("Expected `(`"), token1.tok));
249 }
250 let lparenstok = ast::LeftParensToken { tok: token1.tok };
251 let (number, cursor3) = eat_absnumber(cursor2)?;
252 let (token3, cursor4) = lexer::eat(cursor3)?;
253 if let TokenVariant::RightParens = token3.variant {} else
254 {
255 return Err((String::from("Expected `)`"), token3.tok));
256 }
257 let rparenstok = ast::RightParensToken { tok: token3.tok };
258 let u = ast::U::new(keywordtok, lparenstok, number, rparenstok);
259 cursorlast = cursor4;
260 ast::String_ { alt: Box::new(u) }
261 }
262 TokenVariant::Number(_) | TokenVariant::N | TokenVariant::Read
263 | TokenVariant::Plus | TokenVariant::Minus
264 | TokenVariant::LeftParens =>
265 {
266 let (number, cursor1) = eat_number(cursor0)?;
267 let numtostring = ast::NumToString { num: number };
268 cursorlast = cursor1;
269 ast::String_ { alt: Box::new(numtostring) }
270 }
271 _ => { return Err((String::from("Expected string"), token0.tok)); }
272 };
273
274 let (tokenlast, cursorlastplus1) = lexer::eat(cursorlast)?;
275 match tokenlast.variant
276 {
277 TokenVariant::Plus =>
278 {
279 let plustoken = ast::PlusToken { tok: tokenlast.tok };
280 let (string2, cursorlastplus2) = eat_string(cursorlastplus1)?;
281 let concat = ast::Concat::new(string1, plustoken, string2);
282 Ok((ast::String_ { alt: Box::new(concat) }, cursorlastplus2))
283 }
284 _ => Ok((string1, cursorlast))
285 }
286}
287
288pub fn eat_lineops<'a>(input: &'a str)
289 -> Result<(ast::LineOps<'a>, &'a str), (String, &'a str)>
290{
291 let cursor0 = input;
292 let (number, cursor1) = eat_number(cursor0)?;
293 let (token1, cursor2) = lexer::eat(cursor1)?;
294 match token1.variant
295 {
296 TokenVariant::Comma =>
297 {
298 let numtolineop = ast::NumToLineOp { num: number };
303 let lineop = ast::LineOp::new(ast::SingleLineOp {
304 alt: Box::new(numtolineop)
305 });
306 let commatok = ast::CommaToken { tok: token1.tok };
307 let (lineops, cursor3) = eat_lineops(cursor2)?;
308 let lineoplist = ast::LineOpList::new(lineop, commatok, lineops);
309 Ok((ast::LineOps { alt: Box::new(lineoplist) }, cursor3))
310 }
311 TokenVariant::Sharp =>
312 {
313 let sharptok = ast::SharpToken { tok: token1.tok };
317 let (count, cursor3) = eat_number(cursor2)?;
318 let countlineop = ast::CountLineOp::new(number, sharptok, count);
319 let lineop = ast::LineOp::new(ast::SingleLineOp {
320 alt: Box::new(countlineop) });
321
322 let (token3, cursor4) = lexer::eat(cursor3)?;
323 match token3.variant
324 {
325 TokenVariant::Comma =>
326 {
327 let commatok = ast::CommaToken { tok: token3.tok };
330 let (lineops, cursor5) = eat_lineops(cursor4)?;
331 let lineoplist = ast::LineOpList::new(lineop,
332 commatok,
333 lineops);
334 Ok((ast::LineOps { alt: Box::new(lineoplist) }, cursor5))
335 }
336 _ => Ok((ast::LineOps { alt: Box::new(lineop) }, cursor3))
337 }
338 }
339 _ =>
340 {
341 let numtolineop = ast::NumToLineOp { num: number };
345 let lineop = ast::LineOp::new(ast::SingleLineOp {
346 alt: Box::new(numtolineop) });
347 Ok((ast::LineOps { alt: Box::new(lineop) }, cursor1))
348 }
349 }
350}
351
352pub fn eat_statement<'a>(input: &'a str)
353 -> Result<(ast::Statement<'a>, &'a str), (String, &'a str)>
354{
355 let cursor0 = input;
356 let (token0, cursor1) = lexer::eat(cursor0)?;
357 match token0.variant
358 {
359 TokenVariant::Again =>
360 {
361 let keywordtok = ast::AgainToken { tok: token0.tok };
362 let (token1, cursor2) = lexer::eat(cursor1)?;
363 if let TokenVariant::LeftParens = token1.variant {} else
364 {
365 return Err((String::from("Expected `(`"), token1.tok));
366 }
367 let lparenstok = ast::LeftParensToken { tok: token1.tok };
368 let (boolean, cursor3) = eat_boolean(cursor2)?;
369 let (token3, cursor4) = lexer::eat(cursor3)?;
370 if let TokenVariant::RightParens = token3.variant {} else
371 {
372 return Err((String::from("Expected `)`"), token3.tok));
373 }
374 let rparenstok = ast::RightParensToken { tok: token3.tok };
375 let (statement, cursor5) = eat_statement(cursor4)?;
376 let again = ast::Again::new(keywordtok,
377 lparenstok,
378 boolean,
379 rparenstok,
380 statement);
381 Ok((ast::Statement { alt: Box::new(again) }, cursor5))
382 }
383 TokenVariant::Defer =>
384 {
385 let keywordtok = ast::DeferToken { tok: token0.tok };
386 let (token1, cursor2) = lexer::eat(cursor1)?;
387 if let TokenVariant::LeftParens = token1.variant {} else
388 {
389 return Err((String::from("Expected `(`"), token1.tok));
390 }
391 let lparenstok = ast::LeftParensToken { tok: token1.tok };
392 let (boolean, cursor3) = eat_boolean(cursor2)?;
393 let (token3, cursor4) = lexer::eat(cursor3)?;
394 if let TokenVariant::RightParens = token3.variant {} else
395 {
396 return Err((String::from("Expected `)`"), token3.tok));
397 }
398 let rparenstok = ast::RightParensToken { tok: token3.tok };
399 let (statement, cursor5) = eat_statement(cursor4)?;
400 let defer = ast::Defer::new(keywordtok,
401 lparenstok,
402 boolean,
403 rparenstok,
404 statement);
405 Ok((ast::Statement { alt: Box::new(defer) }, cursor5))
406 }
407 TokenVariant::Forget =>
408 {
409 let keywordtok = ast::ForgetToken { tok: token0.tok };
410 let (token1, cursor2) = lexer::eat(cursor1)?;
411 if let TokenVariant::LeftParens = token1.variant {} else
412 {
413 return Err((String::from("Expected `(`"), token1.tok));
414 }
415 let lparenstok = ast::LeftParensToken { tok: token1.tok };
416 let (boolean, cursor3) = eat_boolean(cursor2)?;
417 let (token3, cursor4) = lexer::eat(cursor3)?;
418 if let TokenVariant::RightParens = token3.variant {} else
419 {
420 return Err((String::from("Expected `)`"), token3.tok));
421 }
422 let rparenstok = ast::RightParensToken { tok: token3.tok };
423 let (statement, cursor5) = eat_statement(cursor4)?;
424 let forget = ast::Forget::new(keywordtok,
425 lparenstok,
426 boolean,
427 rparenstok,
428 statement);
429 Ok((ast::Statement { alt: Box::new(forget) }, cursor5))
430 }
431 TokenVariant::Print =>
432 {
433 let keywordtok = ast::PrintToken { tok: token0.tok };
434 let (token1, cursor2) = lexer::eat(cursor1)?;
435 if let TokenVariant::LeftParens = token1.variant {} else
436 {
437 return Err((String::from("Expected `(`"), token1.tok));
438 }
439 let lparenstok = ast::LeftParensToken { tok: token1.tok };
440 let (string, cursor3) = eat_string(cursor2)?;
441 let (token3, cursor4) = lexer::eat(cursor3)?;
442 if let TokenVariant::RightParens = token3.variant {} else
443 {
444 return Err((String::from("Expected `)`"), token3.tok));
445 }
446 let rparenstok = ast::RightParensToken { tok: token3.tok };
447 let print = ast::Print::new(keywordtok,
448 lparenstok,
449 string,
450 rparenstok);
451 Ok((ast::Statement { alt: Box::new(print) }, cursor4))
452 }
453 TokenVariant::Number(_) | TokenVariant::N | TokenVariant::Read
454 | TokenVariant::Plus | TokenVariant::Minus
455 | TokenVariant::LeftParens | TokenVariant::String
456 | TokenVariant::U =>
457 {
458 let (lineops, cursor1) = eat_lineops(cursor0)?;
459 let lineoperations = ast::LineOperations::new(lineops);
460 Ok((ast::Statement { alt: Box::new(lineoperations) }, cursor1))
461 }
462 _ => Err((String::from("Expected statement"), token0.tok))
463 }
464}
465
466pub fn eat_line<'a>(input: &'a str)
467 -> Result<(ast::Line<'a>, &'a str), (String, &'a str)>
468{
469 let cursor0 = input;
470
471 let (token0, cursor1) = lexer::eat(cursor0)?;
472 let lineno;
473 if let TokenVariant::Number(val) = token0.variant
474 {
475 lineno = ast::NumberToken { tok: token0.tok, val };
476 }
477 else
478 {
479 return Err((String::from("Expected number"), token0.tok));
480 }
481
482 let (statement, cursor2) = eat_statement(cursor1)?;
483
484 let (token2, cursor3) = lexer::eat(cursor2)?;
485 if let TokenVariant::Semicolon = token2.variant {} else
486 {
487 return Err((String::from("Expected `;`"), token2.tok));
488 }
489 let semicolontok = ast::SemicolonToken { tok: token2.tok };
490
491 Ok((ast::Line::new(lineno, statement, semicolontok), cursor3))
492}
493
494#[cfg(test)]
495mod tests {
496 use super::*;
497
498 #[test]
499 fn absnumber_check()
500 {
501 let input = "123abc";
502
503 match eat_absnumber(input)
504 {
505 Ok((root, cursor)) =>
506 {
507 assert_eq!(root.alt.get_str(), &input[..3]);
508 assert_eq!(cursor, &input[3..]);
509 }
510 Err((error, at)) => panic!("{}: {}", error, at)
511 }
512 }
513}