1use crate::lexer::Token;
2
3#[derive(Debug, PartialEq)]
4pub enum Statement {
5 Read(String, String),
6 Write(String, String),
7 Print(String),
8 Append(String, String, String),
9}
10
11pub fn parse(tokens: Vec<Token>) -> Result<Vec<Statement>, String> {
12 let mut statements = Vec::new();
13 let mut tokens_iter = tokens.into_iter().peekable();
14
15 while let Some(token) = tokens_iter.next() {
16 let statement = match token {
17 Token::Read => {
18 let src = get_identifier(&mut tokens_iter)?;
19 tokens_iter.next(); let dest = get_identifier(&mut tokens_iter)?;
21 tokens_iter.next(); Statement::Read(src, dest)
23 }
24 Token::Write => {
25 let path = get_identifier(&mut tokens_iter)?;
26 let content = match tokens_iter.next() {
27 Some(Token::StringLiteral(s)) => s,
28 Some(Token::Identifier(s)) => s,
29 Some(anything) => {
30 return Err(format!("Expected a string literal, got {:?}", anything))
31 }
32 _ => return Err("Expected a string literal.".to_string()),
33 };
34 tokens_iter.next(); Statement::Write(path, content)
36 }
37 Token::Print => {
38 let content = match tokens_iter.next() {
39 Some(Token::StringLiteral(s)) => s,
40 Some(Token::Identifier(s)) => s,
41 Some(anything) => {
42 return Err(format!("Expected a string literal, got {:?}", anything))
43 }
44 _ => return Err("Expected a string literal.".to_string()),
45 };
46 tokens_iter.next(); Statement::Print(content)
48 }
49 Token::Append => {
50 let src1 = get_identifier(&mut tokens_iter)?;
51 let src2 = match tokens_iter.next() {
52 Some(Token::StringLiteral(s)) => s,
53 Some(Token::Identifier(s)) => s,
54 Some(anything) => {
55 return Err(format!("Expected a string literal, got {:?}", anything))
56 }
57 _ => return Err("Expected a string literal.".to_string()),
58 };
59 tokens_iter.next(); let dest = get_identifier(&mut tokens_iter)?;
61 tokens_iter.next(); Statement::Append(src1, src2, dest)
63 }
64 Token::Eol => continue,
65 _ => return Err("Unexpected token.".to_string()),
66 };
67 statements.push(statement);
68 }
69 Ok(statements)
70}
71
72fn get_identifier<I>(tokens_iter: &mut I) -> Result<String, String>
73where
74 I: Iterator<Item = Token>,
75{
76 match tokens_iter.next() {
77 Some(Token::Identifier(s)) => Ok(s),
78 _ => Err("Expected an identifier.".to_string()),
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_parser_basic() {
88 use Token::*;
89
90 let tokens = vec![
91 Read,
92 Identifier("input.txt".to_string()),
93 Arrow,
94 Identifier("content".to_string()),
95 Eol,
96 Write,
97 Identifier("output.txt".to_string()),
98 StringLiteral("Hello, World!".to_string()),
99 Eol,
100 Print,
101 StringLiteral("Hello, World!".to_string()),
102 Eol,
103 Append,
104 Identifier("var1".to_string()),
105 StringLiteral("var2".to_string()),
106 Arrow,
107 Identifier("result".to_string()),
108 Eol,
109 ];
110
111 let ast = parse(tokens).unwrap();
112 let expected = vec![
113 Statement::Read("input.txt".to_string(), "content".to_string()),
114 Statement::Write("output.txt".to_string(), "Hello, World!".to_string()),
115 Statement::Print("Hello, World!".to_string()),
116 Statement::Append("var1".to_string(), "var2".to_string(), "result".to_string()),
117 ];
118 assert_eq!(ast, expected);
119 }
120}