rugs/parser/
module.rs

1use anyhow::Ok;
2
3use super::helpers::error;
4use super::{
5    lexing::{Token, TokenValue},
6    ParserState,
7};
8use crate::ast::*;
9
10impl<'a> ParserState<'a> {
11    pub(super) fn parse_module(&mut self) -> anyhow::Result<Module> {
12        let mut this_module = Module::new();
13        let module_name = if self.is_next(TokenValue::Module)? {
14            let modid = self.parse_module_name()?;
15            if let TokenValue::LeftParen = self.peek_next_token()?.value {
16                let exports = self.parse_paren_list(&mut Self::parse_export)?;
17                this_module.exports = Some(exports);
18            }
19            self.expect(TokenValue::Where)?;
20            modid
21        } else {
22            module("Main")
23        };
24        this_module.name = module_name;
25        self.parse_body(&mut this_module)?;
26        Ok(this_module)
27    }
28
29    fn parse_body(&mut self, module: &mut Module) -> anyhow::Result<()> {
30        let brace = self.get_next_token()?;
31        let is_virtual = match brace.value {
32            TokenValue::LeftBrace => false,
33            TokenValue::VirtualLeftBrace => true,
34            _ => return error("Missing brace at start of body", brace.location),
35        };
36        let tok = self.peek_next_token()?;
37        let imports = match tok.value {
38            TokenValue::Import => self.parse_import_declarations()?,
39            _ => Vec::new(),
40        };
41        let decls = self.parse_top_declarations()?;
42        if is_virtual {
43            self.expect(TokenValue::VirtualRightBrace)?;
44        } else {
45            self.expect(TokenValue::RightBrace)?;
46        }
47        module.declarations = decls;
48        module.imports = imports;
49        Ok(())
50    }
51
52    fn parse_export(&mut self) -> anyhow::Result<Export> {
53        let tok = self.get_next_token()?;
54        match tok.value {
55            TokenValue::QVarId(_, _) | TokenValue::VarId(_) => {
56                Ok(Export::Var(Identifier::try_from(tok)?))
57            }
58            TokenValue::QConId(_, _) | TokenValue::ConId(_) => {
59                let id = Identifier::try_from(tok)?;
60                let spec = self.parse_exposed_spec()?;
61                Ok(Export::TypeOrClass(id, spec))
62            }
63            TokenValue::Module => {
64                let tok = self.get_next_token()?;
65                let modid = Identifier::try_from(tok)?;
66                Ok(Export::Module(modid))
67            }
68            _ => error("Invalid export", tok.location),
69        }
70    }
71
72    fn parse_import_declarations(&mut self) -> anyhow::Result<Vec<ImportDecl>> {
73        let mut imports = Vec::new();
74        loop {
75            if self.is_next(TokenValue::Import)? {
76                imports.push(self.parse_import_decl()?);
77                let tok = self.peek_next_token()?;
78                match tok.value {
79                    TokenValue::Semicolon => {
80                        self.get_next_token()?;
81                    }
82                    TokenValue::RightBrace | TokenValue::VirtualRightBrace => break,
83                    _ => return error("expected semicolon or right brace", tok.location),
84                }
85            } else {
86                break;
87            }
88        }
89        Ok(imports)
90    }
91
92    fn parse_import_decl(&mut self) -> anyhow::Result<ImportDecl> {
93        let qualified = self.is_next(Token::varid("qualified").value)?;
94        let modid = self.parse_module_name()?;
95        let mut import = self.new_import_decl(modid);
96        import.qualified = qualified;
97        if self.is_next(Token::varid("as").value)? {
98            let alias = self.parse_module_name()?;
99            import.alias = Some(alias);
100        }
101        let hiding = self.is_next(Token::varid("hiding").value)?;
102        if self.peek_next(TokenValue::LeftParen)? {
103            let impspec = self.parse_paren_list(&mut Self::parse_import)?;
104            if hiding {
105                import.hidden = Some(impspec);
106            } else {
107                import.specific = Some(impspec);
108            }
109        } else if hiding {
110            return error("No list after `hiding`", self.get_next_token()?.location);
111        }
112        Ok(import)
113    }
114
115    fn parse_import(&mut self) -> anyhow::Result<Import> {
116        let tok = self.get_next_token()?;
117        match tok.value {
118            TokenValue::QVarId(_, _) | TokenValue::VarId(_) => {
119                Ok(Import::Var(Identifier::try_from(tok)?))
120            }
121            TokenValue::QConId(_, _) | TokenValue::ConId(_) => {
122                let id = Identifier::try_from(tok)?;
123                let spec = self.parse_exposed_spec()?;
124                Ok(Import::TypeOrClass(id, spec))
125            }
126            _ => error("Invalid import", tok.location),
127        }
128    }
129
130    fn parse_module_name(&mut self) -> anyhow::Result<Identifier> {
131        let mod_tok = self.get_next_token()?;
132        match mod_tok.value {
133            TokenValue::ConId(s) => Ok(module(&s)),
134            TokenValue::QConId(m, s) => {
135                let mut mid = m.clone();
136                mid.push('.');
137                mid.push_str(&s);
138                Ok(module(&mid))
139            }
140            _ => error(
141                &format!("Invalid module name token {:?}", mod_tok),
142                mod_tok.location,
143            ),
144        }
145    }
146
147    fn parse_exposed_spec(&mut self) -> anyhow::Result<ExposedSpec> {
148        if self.is_next(TokenValue::LeftParen)? {
149            let tok = self.peek_next_token()?;
150            match tok.value {
151                TokenValue::DotDot => {
152                    self.get_next_token()?;
153                    self.expect(TokenValue::RightParen)?;
154                    Ok(ExposedSpec::All)
155                }
156                _ => {
157                    self.rewind_lexer(1);
158                    let cons = self.parse_paren_list(&mut Self::parse_cname)?;
159                    Ok(ExposedSpec::List(cons))
160                }
161            }
162        } else {
163            Ok(ExposedSpec::None)
164        }
165    }
166}