4 * indicated by a double newline - `\n\n`. |
4 * indicated by a double newline - `\n\n`. |
5 * |
5 * |
6 * For example, a nullary command like PING will be actually sent as `PING\n\n`. |
6 * For example, a nullary command like PING will be actually sent as `PING\n\n`. |
7 * A unary command, such as `START_GAME nick` will be actually sent as `START_GAME\nnick\n\n`. |
7 * A unary command, such as `START_GAME nick` will be actually sent as `START_GAME\nnick\n\n`. |
8 */ |
8 */ |
9 use nom::*; |
9 use nom::{ |
|
10 branch::alt, |
|
11 bytes::complete::{tag, tag_no_case, take_until, take_while}, |
|
12 character::complete::{newline, not_line_ending}, |
|
13 combinator::peek, |
|
14 error::{ErrorKind, ParseError}, |
|
15 multi::separated_list, |
|
16 sequence::{pairc, precededc, terminatedc}, |
|
17 Err, IResult, |
|
18 }; |
|
19 |
10 use std::{ |
20 use std::{ |
11 num::ParseIntError, |
21 num::ParseIntError, |
12 ops::Range, |
22 ops::Range, |
13 str, |
23 str, |
14 str::{FromStr, Utf8Error}, |
24 str::{FromStr, Utf8Error}, |
119 ))(input) |
129 ))(input) |
120 } |
130 } |
121 |
131 |
122 fn opt_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> { |
132 fn opt_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> { |
123 alt(( |
133 alt(( |
124 |i: &'a [u8]| peek!(i, end_of_message).map(|(i, _)| (i, None)), |
134 |i| peek(end_of_message)(i).map(|(i, _)| (i, None)), |
125 |i| precededc(i, hw_tag("\n"), a_line).map(|(i, v)| (i, Some(v))), |
135 |i| precededc(i, hw_tag("\n"), a_line).map(|(i, v)| (i, Some(v))), |
126 ))(input) |
136 ))(input) |
127 } |
137 } |
128 |
138 |
129 fn spaces(input: &[u8]) -> HwResult<&[u8]> { |
139 fn spaces(input: &[u8]) -> HwResult<&[u8]> { |
130 precededc(input, hw_tag(" "), |i| take_while(|c| c == b' ')(i)) |
140 precededc(input, hw_tag(" "), |i| take_while(|c| c == b' ')(i)) |
131 } |
141 } |
132 |
142 |
133 fn opt_space_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> { |
143 fn opt_space_arg<'a>(input: &'a [u8]) -> HwResult<'a, Option<String>> { |
134 alt(( |
144 alt(( |
135 |i: &'a [u8]| peek!(i, end_of_message).map(|(i, _)| (i, None)), |
145 |i| peek(end_of_message)(i).map(|(i, _)| (i, None)), |
136 |i| precededc(i, spaces, a_line).map(|(i, v)| (i, Some(v))), |
146 |i| precededc(i, spaces, a_line).map(|(i, v)| (i, Some(v))), |
137 ))(input) |
147 ))(input) |
138 } |
148 } |
139 |
149 |
140 fn hedgehog_array(input: &[u8]) -> HwResult<[HedgehogInfo; 8]> { |
150 fn hedgehog_array(input: &[u8]) -> HwResult<[HedgehogInfo; 8]> { |
141 fn hedgehog_line(input: &[u8]) -> HwResult<HedgehogInfo> { |
151 fn hedgehog_line(input: &[u8]) -> HwResult<HedgehogInfo> { |
142 let (i, name) = terminatedc(input, a_line, eol)?; |
152 let (i, name) = terminatedc(input, a_line, newline)?; |
143 let (i, hat) = a_line(i)?; |
153 let (i, hat) = a_line(i)?; |
144 Ok((i, HedgehogInfo { name, hat })) |
154 Ok((i, HedgehogInfo { name, hat })) |
145 } |
155 } |
146 |
156 |
147 let (i, h1) = terminatedc(input, hedgehog_line, eol)?; |
157 let (i, h1) = terminatedc(input, hedgehog_line, newline)?; |
148 let (i, h2) = terminatedc(i, hedgehog_line, eol)?; |
158 let (i, h2) = terminatedc(i, hedgehog_line, newline)?; |
149 let (i, h3) = terminatedc(i, hedgehog_line, eol)?; |
159 let (i, h3) = terminatedc(i, hedgehog_line, newline)?; |
150 let (i, h4) = terminatedc(i, hedgehog_line, eol)?; |
160 let (i, h4) = terminatedc(i, hedgehog_line, newline)?; |
151 let (i, h5) = terminatedc(i, hedgehog_line, eol)?; |
161 let (i, h5) = terminatedc(i, hedgehog_line, newline)?; |
152 let (i, h6) = terminatedc(i, hedgehog_line, eol)?; |
162 let (i, h6) = terminatedc(i, hedgehog_line, newline)?; |
153 let (i, h7) = terminatedc(i, hedgehog_line, eol)?; |
163 let (i, h7) = terminatedc(i, hedgehog_line, newline)?; |
154 let (i, h8) = hedgehog_line(i)?; |
164 let (i, h8) = hedgehog_line(i)?; |
155 |
165 |
156 Ok((i, [h1, h2, h3, h4, h5, h6, h7, h8])) |
166 Ok((i, [h1, h2, h3, h4, h5, h6, h7, h8])) |
157 } |
167 } |
158 |
168 |
343 |i| cfgc_single_arg(i, "SEED", a_line, GameCfg::Seed), |
353 |i| cfgc_single_arg(i, "SEED", a_line, GameCfg::Seed), |
344 |i| cfgc_single_arg(i, "DRAWNMAP", a_line, GameCfg::DrawnMap), |
354 |i| cfgc_single_arg(i, "DRAWNMAP", a_line, GameCfg::DrawnMap), |
345 |i| { |
355 |i| { |
346 precededc( |
356 precededc( |
347 i, |
357 i, |
348 |i| terminatedc(i, hw_tag("AMMO"), eol), |
358 |i| terminatedc(i, hw_tag("AMMO"), newline), |
349 |i| { |
359 |i| { |
350 let (i, name) = a_line(i)?; |
360 let (i, name) = a_line(i)?; |
351 let (i, value) = opt_arg(i)?; |
361 let (i, value) = opt_arg(i)?; |
352 Ok((i, GameCfg::Ammo(name, value))) |
362 Ok((i, GameCfg::Ammo(name, value))) |
353 }, |
363 }, |
354 ) |
364 ) |
355 }, |
365 }, |
356 |i| { |
366 |i| { |
357 precededc( |
367 precededc( |
358 i, |
368 i, |
359 |i| terminatedc(i, hw_tag("SCHEME"), eol), |
369 |i| terminatedc(i, hw_tag("SCHEME"), newline), |
360 |i| { |
370 |i| { |
361 let (i, name) = a_line(i)?; |
371 let (i, name) = a_line(i)?; |
362 let (i, values) = alt(( |
372 let (i, values) = alt(( |
363 |i: &'a [u8]| peek!(i, end_of_message).map(|(i, _)| (i, None)), |
373 |i| peek(end_of_message)(i).map(|(i, _)| (i, None)), |
364 |i| { |
374 |i| { |
365 precededc(i, eol, |i| separated_list(eol, a_line)(i)) |
375 precededc(i, newline, |i| separated_list(newline, a_line)(i)) |
366 .map(|(i, v)| (i, Some(v))) |
376 .map(|(i, v)| (i, Some(v))) |
367 }, |
377 }, |
368 ))(i)?; |
378 ))(i)?; |
369 Ok((i, GameCfg::Scheme(name, values.unwrap_or_default()))) |
379 Ok((i, GameCfg::Scheme(name, values.unwrap_or_default()))) |
370 }, |
380 }, |
399 fn complex_message(input: &[u8]) -> HwResult<HwProtocolMessage> { |
409 fn complex_message(input: &[u8]) -> HwResult<HwProtocolMessage> { |
400 alt(( |
410 alt(( |
401 |i| { |
411 |i| { |
402 precededc( |
412 precededc( |
403 i, |
413 i, |
404 |i| terminatedc(i, hw_tag("PASSWORD"), eol), |
414 |i| terminatedc(i, hw_tag("PASSWORD"), newline), |
405 |i| { |
415 |i| { |
406 let (i, pass) = terminatedc(i, a_line, eol)?; |
416 let (i, pass) = terminatedc(i, a_line, newline)?; |
407 let (i, salt) = a_line(i)?; |
417 let (i, salt) = a_line(i)?; |
408 Ok((i, Password(pass, salt))) |
418 Ok((i, Password(pass, salt))) |
409 }, |
419 }, |
410 ) |
420 ) |
411 }, |
421 }, |
412 |i| { |
422 |i| { |
413 precededc( |
423 precededc( |
414 i, |
424 i, |
415 |i| terminatedc(i, hw_tag("CHECKER"), eol), |
425 |i| terminatedc(i, hw_tag("CHECKER"), newline), |
416 |i| { |
426 |i| { |
417 let (i, protocol) = terminatedc(i, u16_line, eol)?; |
427 let (i, protocol) = terminatedc(i, u16_line, newline)?; |
418 let (i, name) = terminatedc(i, a_line, eol)?; |
428 let (i, name) = terminatedc(i, a_line, newline)?; |
419 let (i, pass) = a_line(i)?; |
429 let (i, pass) = a_line(i)?; |
420 Ok((i, Checker(protocol, name, pass))) |
430 Ok((i, Checker(protocol, name, pass))) |
421 }, |
431 }, |
422 ) |
432 ) |
423 }, |
433 }, |
424 |i| { |
434 |i| { |
425 precededc( |
435 precededc( |
426 i, |
436 i, |
427 |i| terminatedc(i, hw_tag("CREATE_ROOM"), eol), |
437 |i| terminatedc(i, hw_tag("CREATE_ROOM"), newline), |
428 |i| { |
438 |i| { |
429 let (i, name) = a_line(i)?; |
439 let (i, name) = a_line(i)?; |
430 let (i, pass) = opt_arg(i)?; |
440 let (i, pass) = opt_arg(i)?; |
431 Ok((i, CreateRoom(name, pass))) |
441 Ok((i, CreateRoom(name, pass))) |
432 }, |
442 }, |
433 ) |
443 ) |
434 }, |
444 }, |
435 |i| { |
445 |i| { |
436 precededc( |
446 precededc( |
437 i, |
447 i, |
438 |i| terminatedc(i, hw_tag("JOIN_ROOM"), eol), |
448 |i| terminatedc(i, hw_tag("JOIN_ROOM"), newline), |
439 |i| { |
449 |i| { |
440 let (i, name) = a_line(i)?; |
450 let (i, name) = a_line(i)?; |
441 let (i, pass) = opt_arg(i)?; |
451 let (i, pass) = opt_arg(i)?; |
442 Ok((i, JoinRoom(name, pass))) |
452 Ok((i, JoinRoom(name, pass))) |
443 }, |
453 }, |
444 ) |
454 ) |
445 }, |
455 }, |
446 |i| { |
456 |i| { |
447 precededc( |
457 precededc( |
448 i, |
458 i, |
449 |i| terminatedc(i, hw_tag("ADD_TEAM"), eol), |
459 |i| terminatedc(i, hw_tag("ADD_TEAM"), newline), |
450 |i| { |
460 |i| { |
451 let (i, name) = terminatedc(i, a_line, eol)?; |
461 let (i, name) = terminatedc(i, a_line, newline)?; |
452 let (i, color) = terminatedc(i, u8_line, eol)?; |
462 let (i, color) = terminatedc(i, u8_line, newline)?; |
453 let (i, grave) = terminatedc(i, a_line, eol)?; |
463 let (i, grave) = terminatedc(i, a_line, newline)?; |
454 let (i, fort) = terminatedc(i, a_line, eol)?; |
464 let (i, fort) = terminatedc(i, a_line, newline)?; |
455 let (i, voice_pack) = terminatedc(i, a_line, eol)?; |
465 let (i, voice_pack) = terminatedc(i, a_line, newline)?; |
456 let (i, flag) = terminatedc(i, a_line, eol)?; |
466 let (i, flag) = terminatedc(i, a_line, newline)?; |
457 let (i, difficulty) = terminatedc(i, u8_line, eol)?; |
467 let (i, difficulty) = terminatedc(i, u8_line, newline)?; |
458 let (i, hedgehogs) = hedgehog_array(i)?; |
468 let (i, hedgehogs) = hedgehog_array(i)?; |
459 Ok(( |
469 Ok(( |
460 i, |
470 i, |
461 AddTeam(Box::new(TeamInfo { |
471 AddTeam(Box::new(TeamInfo { |
462 owner: String::new(), |
472 owner: String::new(), |
475 ) |
485 ) |
476 }, |
486 }, |
477 |i| { |
487 |i| { |
478 precededc( |
488 precededc( |
479 i, |
489 i, |
480 |i| terminatedc(i, hw_tag("HH_NUM"), eol), |
490 |i| terminatedc(i, hw_tag("HH_NUM"), newline), |
481 |i| { |
491 |i| { |
482 let (i, name) = terminatedc(i, a_line, eol)?; |
492 let (i, name) = terminatedc(i, a_line, newline)?; |
483 let (i, count) = u8_line(i)?; |
493 let (i, count) = u8_line(i)?; |
484 Ok((i, SetHedgehogsNumber(name, count))) |
494 Ok((i, SetHedgehogsNumber(name, count))) |
485 }, |
495 }, |
486 ) |
496 ) |
487 }, |
497 }, |
488 |i| { |
498 |i| { |
489 precededc( |
499 precededc( |
490 i, |
500 i, |
491 |i| terminatedc(i, hw_tag("TEAM_COLOR"), eol), |
501 |i| terminatedc(i, hw_tag("TEAM_COLOR"), newline), |
492 |i| { |
502 |i| { |
493 let (i, name) = terminatedc(i, a_line, eol)?; |
503 let (i, name) = terminatedc(i, a_line, newline)?; |
494 let (i, color) = u8_line(i)?; |
504 let (i, color) = u8_line(i)?; |
495 Ok((i, SetTeamColor(name, color))) |
505 Ok((i, SetTeamColor(name, color))) |
496 }, |
506 }, |
497 ) |
507 ) |
498 }, |
508 }, |
499 |i| { |
509 |i| { |
500 precededc( |
510 precededc( |
501 i, |
511 i, |
502 |i| terminatedc(i, hw_tag("BAN"), eol), |
512 |i| terminatedc(i, hw_tag("BAN"), newline), |
503 |i| { |
513 |i| { |
504 let (i, n) = terminatedc(i, a_line, eol)?; |
514 let (i, n) = terminatedc(i, a_line, newline)?; |
505 let (i, r) = terminatedc(i, a_line, eol)?; |
515 let (i, r) = terminatedc(i, a_line, newline)?; |
506 let (i, t) = u32_line(i)?; |
516 let (i, t) = u32_line(i)?; |
507 Ok((i, Ban(n, r, t))) |
517 Ok((i, Ban(n, r, t))) |
508 }, |
518 }, |
509 ) |
519 ) |
510 }, |
520 }, |
511 |i| { |
521 |i| { |
512 precededc( |
522 precededc( |
513 i, |
523 i, |
514 |i| terminatedc(i, hw_tag("BAN_IP"), eol), |
524 |i| terminatedc(i, hw_tag("BAN_IP"), newline), |
515 |i| { |
525 |i| { |
516 let (i, n) = terminatedc(i, a_line, eol)?; |
526 let (i, n) = terminatedc(i, a_line, newline)?; |
517 let (i, r) = terminatedc(i, a_line, eol)?; |
527 let (i, r) = terminatedc(i, a_line, newline)?; |
518 let (i, t) = u32_line(i)?; |
528 let (i, t) = u32_line(i)?; |
519 Ok((i, BanIP(n, r, t))) |
529 Ok((i, BanIP(n, r, t))) |
520 }, |
530 }, |
521 ) |
531 ) |
522 }, |
532 }, |
523 |i| { |
533 |i| { |
524 precededc( |
534 precededc( |
525 i, |
535 i, |
526 |i| terminatedc(i, hw_tag("BAN_NICK"), eol), |
536 |i| terminatedc(i, hw_tag("BAN_NICK"), newline), |
527 |i| { |
537 |i| { |
528 let (i, n) = terminatedc(i, a_line, eol)?; |
538 let (i, n) = terminatedc(i, a_line, newline)?; |
529 let (i, r) = terminatedc(i, a_line, eol)?; |
539 let (i, r) = terminatedc(i, a_line, newline)?; |
530 let (i, t) = u32_line(i)?; |
540 let (i, t) = u32_line(i)?; |
531 Ok((i, BanNick(n, r, t))) |
541 Ok((i, BanNick(n, r, t))) |
532 }, |
542 }, |
533 ) |
543 ) |
534 }, |
544 }, |