An awful programming language.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

73 lines
1.8KB

  1. use std;
  2. use {Expr};
  3. pub enum ParseError {
  4. TrailingCharacters,
  5. UnexpectedEof,
  6. EmptyBlock,
  7. IOError(std::io::Error)
  8. }
  9. impl From<std::io::Error> for ParseError {
  10. fn from(err: std::io::Error) -> ParseError {
  11. ParseError::IOError(err)
  12. }
  13. }
  14. pub fn parse(mut src: impl std::io::Read) -> Result<Expr, ParseError> {
  15. let mut buf = [0];
  16. let next = parse_next(&mut src, &mut buf)?;
  17. let ret = src.read(&mut buf)?;
  18. if ret > 0 {
  19. Err(ParseError::TrailingCharacters)
  20. }
  21. else {
  22. match next {
  23. Next::EndFile => Err(ParseError::UnexpectedEof),
  24. Next::EndParen => Err(ParseError::TrailingCharacters),
  25. Next::Expr(expr) => Ok(expr)
  26. }
  27. }
  28. }
  29. enum Next {
  30. Expr(Expr),
  31. EndParen,
  32. EndFile
  33. }
  34. fn parse_next(mut src: impl std::io::Read, buf: &mut [u8; 1]) -> Result<Next, ParseError> {
  35. loop {
  36. let ret = src.read(buf)?;
  37. if ret < 1 {
  38. return Ok(Next::EndFile);
  39. }
  40. if buf[0] == b'4' {
  41. return Ok(Next::Expr(Expr::Four));
  42. }
  43. if buf[0] == b')' {
  44. return Ok(Next::EndParen);
  45. }
  46. if buf[0] == b'(' {
  47. return Ok(Next::Expr(parse_call(src, buf)?));
  48. }
  49. }
  50. }
  51. fn parse_call(mut src: impl std::io::Read, buf: &mut [u8; 1]) -> Result<Expr, ParseError> {
  52. let mut args = match parse_next(&mut src, buf)? {
  53. Next::EndFile => return Err(ParseError::UnexpectedEof),
  54. Next::EndParen => return Err(ParseError::EmptyBlock),
  55. Next::Expr(expr) => vec1![expr]
  56. };
  57. loop {
  58. match parse_next(&mut src, buf)? {
  59. Next::EndFile => return Err(ParseError::UnexpectedEof),
  60. Next::EndParen => return Ok(Expr::Call(args)),
  61. Next::Expr(expr) => args.push(expr)
  62. }
  63. }
  64. }