sdml_parse/parse/
modules.rs

1use std::str::FromStr;
2
3use super::ParseContext;
4use crate::parse::annotations::parse_annotation;
5use crate::parse::definitions::parse_definition;
6use crate::parse::identifiers::{parse_identifier, parse_qualified_identifier};
7use crate::parse::parse_comment;
8use sdml_core::error::Error;
9use sdml_core::load::ModuleLoader as ModuleLoaderTrait;
10use sdml_core::model::annotations::HasAnnotations;
11use sdml_core::model::identifiers::Identifier;
12use sdml_core::model::modules::Module;
13use sdml_core::model::modules::{
14    HeaderValue, Import, ImportStatement, MemberImport, ModuleImport, ModulePath,
15};
16use sdml_core::model::HasSourceSpan;
17use sdml_core::syntax::{
18    FIELD_NAME_BASE, FIELD_NAME_BODY, FIELD_NAME_NAME, FIELD_NAME_RENAME, FIELD_NAME_SEGMENT,
19    FIELD_NAME_VERSION_INFO, FIELD_NAME_VERSION_URI, NODE_KIND_ANNOTATION, NODE_KIND_DEFINITION,
20    NODE_KIND_FROM_CLAUSE, NODE_KIND_IDENTIFIER, NODE_KIND_IMPORT_STATEMENT, NODE_KIND_IRI,
21    NODE_KIND_LINE_COMMENT, NODE_KIND_MEMBER_IMPORT, NODE_KIND_MODULE_BODY,
22    NODE_KIND_MODULE_IMPORT, NODE_KIND_MODULE_PATH_ABSOLUTE, NODE_KIND_MODULE_PATH_RELATIVE,
23    NODE_KIND_MODULE_PATH_ROOT, NODE_KIND_QUALIFIED_IDENTIFIER, NODE_KIND_QUOTED_STRING,
24};
25use tree_sitter::{Node, TreeCursor};
26use url::Url;
27
28// ------------------------------------------------------------------------------------------------
29// Parser Functions
30// ------------------------------------------------------------------------------------------------
31
32pub(crate) fn parse_module<'a>(
33    context: &mut ParseContext<'a>,
34    cursor: &mut TreeCursor<'a>,
35) -> Result<Module, Error> {
36    let node = cursor.node();
37    rule_fn!("module", node);
38    context.check_if_error(&node, RULE_NAME)?;
39
40    let child = node_field_named!(
41        context,
42        RULE_NAME,
43        node,
44        FIELD_NAME_NAME,
45        NODE_KIND_IDENTIFIER
46    );
47    let name = parse_identifier(context, &child)?;
48    let mut module = Module::new(name).with_source_span(node.into());
49
50    if let Some(child) =
51        optional_node_field_named!(context, RULE_NAME, node, FIELD_NAME_BASE, NODE_KIND_IRI)
52    {
53        let uri = parse_uri(context, &child)?;
54        module.set_base_uri(HeaderValue::from(uri).with_source_span(child.into()));
55    }
56
57    if let Some(child) = optional_node_field_named!(
58        context,
59        RULE_NAME,
60        node,
61        FIELD_NAME_VERSION_INFO,
62        NODE_KIND_QUOTED_STRING
63    ) {
64        let info = parse_quoted_string(context, &child)?;
65        module.set_version_info(HeaderValue::from(info).with_source_span(child.into()));
66    }
67
68    if let Some(child) = optional_node_field_named!(
69        context,
70        RULE_NAME,
71        node,
72        FIELD_NAME_VERSION_URI,
73        NODE_KIND_IRI
74    ) {
75        let uri = parse_uri(context, &child)?;
76        module.set_version_uri(HeaderValue::from(uri).with_source_span(child.into()));
77    }
78
79    let child = node_field_named!(
80        context,
81        RULE_NAME,
82        node,
83        FIELD_NAME_BODY,
84        NODE_KIND_MODULE_BODY
85    );
86    parse_module_body(context, &mut module, &mut child.walk())?;
87
88    Ok(module)
89}
90
91#[inline(always)]
92fn parse_uri<'a>(context: &mut ParseContext<'a>, node: &Node<'a>) -> Result<Url, Error> {
93    let value = context.node_source(node)?;
94    // TODO: turn into real error!
95    Ok(Url::from_str(&value[1..(value.len() - 1)]).expect("Invalid value for IriReference"))
96}
97
98#[inline(always)]
99fn parse_quoted_string<'a>(
100    context: &mut ParseContext<'a>,
101    node: &Node<'a>,
102) -> Result<String, Error> {
103    let node_value = context.node_source(node)?;
104    Ok(node_value[1..(node_value.len() - 1)].to_string())
105}
106
107fn parse_module_body<'a>(
108    context: &mut ParseContext<'a>,
109    module: &mut Module,
110    cursor: &mut TreeCursor<'a>,
111) -> Result<(), Error> {
112    rule_fn!("module_body", cursor.node());
113
114    for node in cursor.node().named_children(cursor) {
115        check_node!(context, RULE_NAME, &node);
116        match node.kind() {
117            NODE_KIND_IMPORT_STATEMENT => {
118                module.add_to_imports(parse_import_statement(context, &mut node.walk())?);
119            }
120            NODE_KIND_ANNOTATION => {
121                module.add_to_annotations(parse_annotation(context, &mut node.walk())?);
122            }
123            NODE_KIND_DEFINITION => {
124                module.add_to_definitions(parse_definition(context, &mut node.walk())?)?;
125            }
126            NODE_KIND_LINE_COMMENT => {
127                let comment = parse_comment(context, &node)?;
128                context.push_comment(comment);
129            }
130            _ => {
131                unexpected_node!(
132                    context,
133                    RULE_NAME,
134                    node,
135                    [
136                        NODE_KIND_IMPORT_STATEMENT,
137                        NODE_KIND_ANNOTATION,
138                        NODE_KIND_DEFINITION,
139                    ]
140                );
141            }
142        }
143    }
144    Ok(())
145}
146
147fn parse_import_statement<'a>(
148    context: &mut ParseContext<'a>,
149    cursor: &mut TreeCursor<'a>,
150) -> Result<ImportStatement, Error> {
151    rule_fn!("import_statement", cursor.node());
152
153    let mut import = ImportStatement::default().with_source_span(cursor.node().into());
154
155    for node in cursor.node().named_children(cursor) {
156        check_node!(context, RULE_NAME, &node);
157        match node.kind() {
158            NODE_KIND_FROM_CLAUSE => {
159                import.set_from_module_path(parse_from_clause(context, &mut node.walk())?);
160            }
161            NODE_KIND_MODULE_IMPORT => {
162                let child = node_field_named!(
163                    context,
164                    RULE_NAME,
165                    node,
166                    FIELD_NAME_NAME,
167                    NODE_KIND_IDENTIFIER
168                );
169                let mut imported: ModuleImport = parse_identifier(context, &child)?.into();
170                imported.set_source_span(node.into());
171
172                if let Some(child) = optional_node_field_named!(
173                    context,
174                    RULE_NAME,
175                    node,
176                    FIELD_NAME_VERSION_URI,
177                    NODE_KIND_IRI
178                ) {
179                    let uri = parse_uri(context, &child)?;
180                    imported.set_version_uri(HeaderValue::from(uri).with_source_span(child.into()));
181                }
182
183                if let Some(child) = optional_node_field_named!(
184                    context,
185                    RULE_NAME,
186                    node,
187                    FIELD_NAME_RENAME,
188                    NODE_KIND_IDENTIFIER
189                ) {
190                    imported.set_rename_as(parse_identifier(context, &child)?)
191                }
192
193                let imported: Import = imported.into();
194                context.add_import(&imported)?;
195                import.add_to_imports(imported);
196            }
197            NODE_KIND_MEMBER_IMPORT => {
198                let child = node_field_named!(
199                    context,
200                    RULE_NAME,
201                    node,
202                    FIELD_NAME_NAME,
203                    NODE_KIND_QUALIFIED_IDENTIFIER
204                );
205                let mut imported: MemberImport =
206                    parse_qualified_identifier(context, &mut child.walk())?.into();
207                imported.set_source_span(child.into());
208
209                if let Some(child) = optional_node_field_named!(
210                    context,
211                    RULE_NAME,
212                    node,
213                    FIELD_NAME_RENAME,
214                    NODE_KIND_IDENTIFIER
215                ) {
216                    imported.set_rename_as(parse_identifier(context, &child)?)
217                }
218
219                let imported: Import = imported.into();
220                context.add_import(&imported)?;
221                import.add_to_imports(imported);
222            }
223            NODE_KIND_LINE_COMMENT => {}
224            _ => {
225                unexpected_node!(
226                    context,
227                    RULE_NAME,
228                    node,
229                    [
230                        NODE_KIND_FROM_CLAUSE,
231                        NODE_KIND_MODULE_IMPORT,
232                        NODE_KIND_MEMBER_IMPORT,
233                    ]
234                );
235            }
236        }
237    }
238    Ok(import)
239}
240
241fn parse_from_clause<'a>(
242    context: &mut ParseContext<'a>,
243    cursor: &mut TreeCursor<'a>,
244) -> Result<ModulePath, Error> {
245    rule_fn!("from_clause", cursor.node());
246
247    if let Some(child) = cursor.node().named_children(cursor).next() {
248        check_node!(context, RULE_NAME, &child);
249        match child.kind() {
250            NODE_KIND_MODULE_PATH_ABSOLUTE => {
251                return Ok(ModulePath::absolute(parse_module_path(
252                    context,
253                    &mut child.walk(),
254                )?))
255            }
256            NODE_KIND_MODULE_PATH_RELATIVE => {
257                return Ok(ModulePath::relative(parse_module_path(
258                    context,
259                    &mut child.walk(),
260                )?))
261            }
262            NODE_KIND_MODULE_PATH_ROOT => return Ok(ModulePath::root()),
263            _ => {
264                unexpected_node!(
265                    context,
266                    RULE_NAME,
267                    child,
268                    [
269                        NODE_KIND_MODULE_PATH_ABSOLUTE,
270                        NODE_KIND_MODULE_PATH_RELATIVE,
271                        NODE_KIND_MODULE_PATH_ROOT,
272                    ]
273                );
274            }
275        }
276    }
277    unreachable!()
278}
279
280fn parse_module_path<'a>(
281    context: &mut ParseContext<'a>,
282    cursor: &mut TreeCursor<'a>,
283) -> Result<Vec<Identifier>, Error> {
284    rule_fn!("module_path", cursor.node());
285    let mut path = Vec::default();
286
287    for child in cursor
288        .node()
289        .children_by_field_name(FIELD_NAME_SEGMENT, cursor)
290    {
291        check_node!(context, RULE_NAME, &child, NODE_KIND_IDENTIFIER);
292        path.push(parse_identifier(context, &child)?);
293    }
294
295    Ok(path)
296}