Skip to main content

jia_parse/jia_lang/parser/
decl.rs

1//! Variables block parser for the CP language.
2//!
3//! Parses declarations like:
4//! ```text
5//! variables {
6//!   Interval: a, b, c
7//!   Integer: makespan
8//!   Set[Interval]: machine1, machine2
9//! }
10//! ```
11
12use super::Parser;
13use crate::error::ParseError;
14use crate::jia_lang::ast::{VarDecl, VarType};
15use crate::jia_lang::lexer::TokenKind;
16
17impl<'a> Parser<'a> {
18    /// Parse a `variables { ... }` block.
19    pub fn parse_variables_block(&mut self) -> Result<Vec<VarDecl>, ParseError> {
20        self.expect_ident_matching("variables")?;
21        self.expect_token(TokenKind::LBrace)?;
22
23        let mut decls = Vec::new();
24        while self.peek_kind() != Some(TokenKind::RBrace) {
25            decls.push(self.parse_var_decl()?);
26        }
27        self.expect_token(TokenKind::RBrace)?;
28        Ok(decls)
29    }
30
31    /// Parse a single variable declaration: `Type: name1, name2, ...`
32    fn parse_var_decl(&mut self) -> Result<VarDecl, ParseError> {
33        let var_type = self.parse_var_type()?;
34        self.expect_token(TokenKind::Colon)?;
35        let names = self.parse_ident_list()?;
36        Ok(VarDecl { names, var_type })
37    }
38
39    /// Parse a variable type: `Interval`, `Integer`, `Set[Interval]`, `Set[Integer]`
40    fn parse_var_type(&mut self) -> Result<VarType, ParseError> {
41        let name = self.expect_ident()?;
42        match name.as_str() {
43            "Interval" => Ok(VarType::Interval),
44            "Integer" => Ok(VarType::Integer),
45            "Real" => Ok(VarType::Real),
46            "Set" => {
47                self.expect_token(TokenKind::LBracket)?;
48                let inner = self.expect_ident()?;
49                self.expect_token(TokenKind::RBracket)?;
50                match inner.as_str() {
51                    "Interval" => Ok(VarType::SetInterval),
52                    "Integer" => Ok(VarType::SetInteger),
53                    _ => Err(ParseError::new(
54                        format!("expected 'Interval' or 'Integer' in Set[...], got '{inner}'"),
55                        self.current_span(),
56                    )),
57                }
58            }
59            _ => Err(ParseError::new(
60                format!("expected type (Interval, Integer, Real, Set[...]), got '{name}'"),
61                self.current_span(),
62            )),
63        }
64    }
65
66    /// Parse a comma-separated list of identifiers (at least one).
67    pub fn parse_ident_list(&mut self) -> Result<Vec<String>, ParseError> {
68        let mut names = vec![self.expect_ident()?];
69        while self.peek_kind() == Some(TokenKind::Comma) {
70            self.advance();
71            names.push(self.expect_ident()?);
72        }
73        Ok(names)
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use crate::jia_lang::ast::{VarDecl, VarType};
80    use crate::jia_lang::lexer::tokenize;
81    use crate::jia_lang::parser::Parser;
82
83    #[test]
84    fn test_variables_block() {
85        let input = "variables { Interval: a, b Integer: makespan Set[Interval]: m1, m2 }";
86        let tokens = tokenize(input).unwrap();
87        let mut parser = Parser::new(&tokens);
88        let decls = parser.parse_variables_block().unwrap();
89        assert_eq!(
90            decls,
91            vec![
92                VarDecl {
93                    names: vec!["a".to_string(), "b".to_string()],
94                    var_type: VarType::Interval,
95                },
96                VarDecl {
97                    names: vec!["makespan".to_string()],
98                    var_type: VarType::Integer,
99                },
100                VarDecl {
101                    names: vec!["m1".to_string(), "m2".to_string()],
102                    var_type: VarType::SetInterval,
103                },
104            ]
105        );
106    }
107
108    #[test]
109    fn test_set_integer_type() {
110        let input = "variables { Set[Integer]: costs }";
111        let tokens = tokenize(input).unwrap();
112        let mut parser = Parser::new(&tokens);
113        let decls = parser.parse_variables_block().unwrap();
114        assert_eq!(decls[0].var_type, VarType::SetInteger);
115    }
116
117    #[test]
118    fn test_invalid_types() {
119        for input in [
120            "variables { Set[String]: bad }",
121            "variables { Boolean: bad }",
122        ] {
123            let tokens = tokenize(input).unwrap();
124            let mut parser = Parser::new(&tokens);
125            assert!(parser.parse_variables_block().is_err(), "{input}");
126        }
127    }
128}