lexigram_core/lib.rs
1// Copyright (c) 2025 Redglyph (@gmail.com). All Rights Reserved.
2
3pub mod alt;
4pub mod segmap;
5pub mod char_reader;
6pub mod fixed_sym_table;
7pub mod log;
8pub mod lexer;
9pub mod parser;
10pub mod text_span;
11
12// package name & version
13pub const CORE_PKG_NAME: &str = env!("CARGO_PKG_NAME");
14pub const CORE_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
15
16/// ID of a lexer token
17pub type TokenId = u16;
18/// ID of a nonterminal
19pub type VarId = u16;
20/// ID of a rule alternative. We use the same type as [VarId] because they're very similar quantities.
21pub type AltId = VarId;
22
23// ---------------------------------------------------------------------------------------------
24// General helper traits
25
26pub trait CharLen {
27 /// Returns the length in characters (not bytes).
28 fn charlen(&self) -> usize;
29}
30
31impl<T: AsRef<str>> CharLen for T {
32 fn charlen(&self) -> usize {
33 self.as_ref().chars().count()
34 }
35}
36
37/// This trait provides a shortcut for two commonly used iterator adapters.
38///
39/// * [join(...)](CollectJoin::join): joins [ToString] items into a `Vec::<String>` by inserting a separator between them.
40/// * [to_vec(...)](CollectJoin::to_vec): equivalent to `.collect::<Vec<_>>()`
41pub trait CollectJoin {
42 /// Iterator adapter that joins [ToString] items into a `Vec::<String>` by inserting `separator` between them.
43 ///
44 /// ## Example
45 ///
46 /// ```
47 /// # use lexigram_core::CollectJoin;
48 /// let numbers = (0..10).filter(|&x| x < 5).join(", ");
49 /// assert_eq!(numbers, "0, 1, 2, 3, 4");
50 /// ```
51 fn join(&mut self, separator: &str) -> String
52 where Self: Iterator,
53 <Self as Iterator>::Item: ToString
54 {
55 self.map(|x| x.to_string()).collect::<Vec<_>>().join(separator)
56 }
57
58 /// Iterator adapter that joins items into a `Vec<_>`; equivalent to `.collect::<Vec<_>>()`
59 ///
60 /// ## Example
61 ///
62 /// ```
63 /// # use lexigram_core::CollectJoin;
64 /// let values = [1, 5, 10, 25, 50].into_iter().map(|x| x * x).to_vec();
65 /// assert_eq!(values, vec![1, 25, 100, 625, 2500]);
66 /// ```
67 fn to_vec(self) -> Vec<<Self as Iterator>::Item>
68 where Self: Iterator + Sized
69 {
70 self.collect::<Vec<_>>()
71 }
72}
73
74impl<I: Iterator> CollectJoin for I {}
75
76// ---------------------------------------------------------------------------------------------
77// Macros
78
79pub mod macros {
80 /// Generates an `OpCode` instance.
81 ///
82 /// # Examples
83 /// ```
84 /// # use lexigram_core::TokenId;
85 /// # use lexigram_core::opcode;
86 /// # use lexigram_core::VarId;
87 /// # use lexigram_core::parser::OpCode;
88 /// assert_eq!(opcode!(e), OpCode::Empty);
89 /// assert_eq!(opcode!(t 2), OpCode::T(2 as TokenId));
90 /// assert_eq!(opcode!(nt 3), OpCode::NT(3));
91 /// assert_eq!(opcode!(loop 2), OpCode::Loop(2));
92 /// assert_eq!(opcode!(exit 1), OpCode::Exit(1));
93 /// assert_eq!(opcode!(nt 3), OpCode::NT(3));
94 /// assert_eq!(opcode!(loop 2), OpCode::Loop(2));
95 /// assert_eq!(opcode!(exit 1), OpCode::Exit(1));
96 /// assert_eq!(opcode!(hook), OpCode::Hook);
97 /// assert_eq!(opcode!(end), OpCode::End);
98 #[macro_export]
99 macro_rules! opcode {
100 (e) => { $crate::parser::OpCode::Empty };
101 (t $id:expr) => { $crate::parser::OpCode::T($id as $crate::TokenId) };
102 (nt $id:expr) => { $crate::parser::OpCode::NT($id as $crate::VarId) };
103 (loop $id:expr) => { $crate::parser::OpCode::Loop($id as $crate::VarId) };
104 (exit $id:expr) => { $crate::parser::OpCode::Exit($id as $crate::VarId) };
105 (nt $id:expr) => { $crate::parser::OpCode::NT($id as $crate::VarId, 0) };
106 (loop $id:expr) => { $crate::parser::OpCode::Loop($id as $crate::VarId, 0) };
107 (exit $id:expr) => { $crate::parser::OpCode::Exit($id as $crate::VarId, 0) };
108 (hook) => { $crate::parser::OpCode::Hook };
109 (end) => { $crate::parser::OpCode::End };
110 }
111
112 /// Generates an opcode strip. A strip is made up of `OpCode` items separated by a comma.
113 ///
114 /// # Example
115 /// ```
116 /// # use lexigram_core::{TokenId, VarId, strip, opcode};
117 /// # use lexigram_core::alt::Alternative;
118 /// # use lexigram_core::parser::{OpCode, Symbol};
119 /// assert_eq!(strip!(nt 1, loop 5, t 3, e), vec![opcode!(nt 1), opcode!(loop 5), opcode!(t 3), opcode!(e)]);
120 /// ```
121 #[macro_export]
122 macro_rules! strip {
123 () => { std::vec![] };
124 ($($a:ident $($b:expr)?,)+) => { strip![$($a $($b)?),+] };
125 ($($a:ident $($b:expr)?),*) => { std::vec![$($crate::opcode!($a $($b)?)),*] };
126 }
127}