Skip to main content

microcad_lang_parse/lex/
mod.rs

1// Copyright © 2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4use crate::{lex::from_logos::from_logos, token::Token};
5
6use ::logos::Lexer;
7use microcad_lang_base::{Span, Spanned};
8use thiserror::Error;
9
10mod from_logos;
11mod logos;
12
13/// Possible errors encountered while tokenizing
14#[derive(Debug, Default, Clone, PartialEq, Error)]
15pub enum LexerError {
16    /// No valid token was found for the character
17    #[default]
18    #[error("No valid token")]
19    NoValidToken,
20    /// A format string was encountered that wasn't closed correctly
21    #[error("Unclosed format string")]
22    UnclosedStringFormat(Span),
23    /// A string was encountered that wasn't closed correctly
24    #[error("Unclosed string")]
25    UnclosedString(Span),
26}
27
28impl LexerError {
29    /// Get a descriptive name of the error type
30    pub fn kind(&self) -> &'static str {
31        match self {
32            LexerError::NoValidToken => "no valid token",
33            LexerError::UnclosedStringFormat(_) => "unclosed format string",
34            LexerError::UnclosedString(_) => "unclosed string",
35        }
36    }
37}
38
39impl LexerError {
40    /// Get the span of the error
41    pub fn span(&self) -> Option<Span> {
42        match self {
43            LexerError::UnclosedStringFormat(span) => Some(span.clone()),
44            LexerError::UnclosedString(span) => Some(span.clone()),
45            _ => None,
46        }
47    }
48}
49
50/// Tokenize a µcad source string into an iterator of tokens.
51pub fn lex<'a>(input: &'a str) -> impl Iterator<Item = Spanned<Token<'a>>> {
52    from_logos(Lexer::<logos::LogosToken>::new(input).spanned())
53}