Skip to main content

microcad_lang_parse/
lib.rs

1// Copyright © 2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Syntax definitions and parser for µcad source code.
5//!
6//! This module includes the components to parse µcad source code into a stream of tokens or abstract syntax tree.
7//!
8//! - Transform source code into a stream of tokens with [`lex`]
9//! - Create an abstract syntax tree from the list of tokens with [`parse`]
10
11/// Abstract syntax tree for µcad files
12pub mod ast;
13
14/// Tokens
15pub mod token;
16
17/// Contains the parser.
18mod parse;
19
20/// Contains the lexer (aka tokenizer).
21mod lex;
22
23use microcad_lang_base::virtual_url;
24pub use parse::{ParseContext, ParseError, ParseErrors, parsers};
25
26/// Parse trait.
27pub trait Parse: Sized {
28    /// Parse from a context.
29    ///
30    /// The context also contains the source string.
31    fn parse(context: &ParseContext) -> Result<Self, ParseErrors>;
32}
33
34impl Parse for ast::Source {
35    fn parse(context: &ParseContext) -> Result<Self, ParseErrors> {
36        match context {
37            ParseContext::Element(code) => {
38                let ast = crate::parse(code)?;
39                let src_ref = context.src_ref(&ast.span);
40
41                Ok(Self {
42                    url: virtual_url("virtual"),
43                    ast: microcad_lang_base::Refer::new(ast, src_ref),
44                    line_offset: 0,
45                    code: code.clone().map(|s| s.to_string()),
46                })
47            }
48            ParseContext::Source {
49                url,
50                line_offset,
51                code,
52                ..
53            } => {
54                let ast = crate::parse(code.value())?;
55                let src_ref = context.src_ref(&ast.span);
56
57                Ok(Self {
58                    url: url.clone(),
59                    ast: microcad_lang_base::Refer::new(ast, src_ref),
60                    line_offset: *line_offset,
61                    code: code.clone().map(|s| s.to_string()),
62                })
63            }
64        }
65    }
66}
67
68pub use lex::lex;
69
70/// API to parse directly from a string
71pub fn parse(source: &str) -> Result<ast::Program, ParseErrors> {
72    parse::parse(&lex(source).collect::<Vec<_>>())
73}