aiken_lang/
parser.rs

1mod annotation;
2pub mod chain;
3pub mod definition;
4pub mod error;
5pub mod expr;
6pub mod extra;
7pub mod lexer;
8pub mod literal;
9pub mod pattern;
10pub mod token;
11mod utils;
12
13use crate::{ast, line_numbers::LineNumbers};
14pub use annotation::parser as annotation;
15use chumsky::prelude::*;
16pub use definition::{import::parser as import, parser as definition};
17use error::ParseError;
18pub use expr::parser as expression;
19use extra::ModuleExtra;
20use indexmap::IndexMap;
21pub use pattern::parser as pattern;
22
23pub fn module(
24    src: &str,
25    kind: ast::ModuleKind,
26) -> Result<(ast::UntypedModule, ModuleExtra), Vec<ParseError>> {
27    let lexer::LexInfo { tokens, extra } = lexer::run(src)?;
28
29    let stream = chumsky::Stream::from_iter(ast::Span::create(tokens.len(), 1), tokens.into_iter());
30
31    let definitions = import()
32        .repeated()
33        .map(|imports| {
34            let mut store = IndexMap::new();
35
36            for import in imports.into_iter() {
37                let key = (import.module, import.as_name);
38                match store.remove(&key) {
39                    None => {
40                        store.insert(key, (import.location, import.unqualified));
41                    }
42                    Some((location, unqualified)) => {
43                        let mut merged_unqualified = Vec::new();
44                        merged_unqualified.extend(unqualified.1);
45                        merged_unqualified.extend(import.unqualified.1);
46                        store.insert(key, (location, (unqualified.0, merged_unqualified)));
47                    }
48                }
49            }
50
51            store
52                .into_iter()
53                .map(|((module, as_name), (location, unqualified))| {
54                    ast::Definition::Use(ast::Use {
55                        module,
56                        as_name,
57                        location,
58                        unqualified,
59                        package: (),
60                    })
61                })
62                .collect::<Vec<ast::UntypedDefinition>>()
63        })
64        .then(definition().repeated())
65        .map(|(imports, others)| {
66            let mut defs = Vec::new();
67            defs.extend(imports);
68            defs.extend(others);
69            defs
70        })
71        .then_ignore(end())
72        .parse(stream)?;
73
74    let lines = LineNumbers::new(src);
75
76    let module = ast::UntypedModule {
77        kind,
78        lines,
79        definitions,
80        docs: vec![],
81        name: "".to_string(),
82        type_info: (),
83    };
84
85    Ok((module, extra))
86}
87
88#[cfg(test)]
89mod tests {
90    use crate::assert_module;
91
92    #[test]
93    fn merge_imports() {
94        assert_module!(
95            r#"
96            use aiken/list.{bar, foo}
97            use aiken/list.{baz}
98            "#
99        );
100    }
101
102    #[test]
103    fn windows_newline() {
104        assert_module!("use aiken/list\r\n");
105    }
106
107    #[test]
108    fn can_handle_comments_at_end_of_file() {
109        assert_module!(
110            r#"
111            use aiken
112
113            // some comment
114            // more comments"#
115        );
116    }
117
118    #[test]
119    fn function_ambiguous_sequence() {
120        assert_module!(
121            r#"
122            fn foo_1() {
123              let a = bar
124              (40)
125            }
126
127            fn foo_2() {
128              let a = bar
129              {40}
130            }
131
132            fn foo_3() {
133              let a = (40+2)
134            }
135
136            fn foo_4() {
137              let a = bar(42)
138              (a + 14) * 42
139            }
140            "#
141        );
142    }
143
144    #[test]
145    fn parse_unicode_offset_1() {
146        assert_module!(
147            r#"
148            fn foo() {
149              let x = "★"
150              x
151            }
152            "#
153        );
154    }
155
156    #[test]
157    fn parse_unicode_offset_2() {
158        assert_module!(
159            r#"
160            fn foo() {
161              let x = "*"
162              x
163            }
164            "#
165        );
166    }
167}