1use py_lex::*;
2use terl::*;
3type Result<T> = terl::Result<T, terl::ParseError>;
4
5mod expr;
6mod flow;
7mod item;
8mod stmt;
9mod types;
10
11pub use expr::*;
12pub use flow::*;
13pub use item::*;
14pub use stmt::*;
15pub use types::*;
16
17#[derive(Debug, Clone)]
18pub struct Ident(String);
19
20impl std::ops::Deref for Ident {
21 type Target = str;
22
23 fn deref(&self) -> &Self::Target {
24 &self.0
25 }
26}
27
28impl std::fmt::Display for Ident {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 self.0.fmt(f)
31 }
32}
33
34impl ParseUnit<Token> for Ident {
35 type Target = Ident;
36
37 fn parse(p: &mut Parser<Token>) -> ParseResult<Self, Token> {
38 let Some(token) = p.next() else {
39 return p.unmatch("expect a `Ident`, but no token left");
40 };
41
42 if token.chars().next().is_some_and(|c| c.is_ascii_digit()) {
43 return p.unmatch("bad ident! ident should not start with a digit");
44 }
45
46 use py_lex::*;
47
48 let keeps = &[
49 ops::KEPPING_KEYWORDS,
50 ops::sub_classes::KEPPING_KEYWORDS,
51 preprocess::KEPPING_KEYWORDS,
52 syntax::KEPPING_KEYWORDS,
53 types::KEPPING_KEYWORDS,
54 ];
55
56 for keeps in keeps {
57 if keeps.with(|keeps| keeps.contains(&**token)) {
58 return p.unmatch("keeping keywords could not be ident");
59 }
60 }
61
62 Ok(Ident(token.string.clone()))
64 }
65}
66
67#[macro_export]
69macro_rules! complex_pu {
70 (
71 $(#[$metas:meta])*
72 cpu $enum_name:ident {
73 $(
74 $(#[$v_metas:meta])*
75 $variant:ident
76 ),*
77 }) => {
78 #[derive(Debug, Clone)]
79 $(#[$metas])*
80 pub enum $enum_name {
81 $(
82 $(#[$v_metas])*
83 $variant($variant),
84 )*
85 }
86
87 $(
88 impl From<$variant> for $enum_name {
89 fn from(v: $variant) -> $enum_name {
90 <$enum_name>::$variant(v)
91 }
92 }
93 )*
94
95
96 impl terl::ParseUnit<py_lex::Token> for $enum_name {
97 type Target = $enum_name;
98
99 fn parse(p: &mut terl::Parser<py_lex::Token>) -> terl::ParseResult<Self, py_lex::Token>
100 {
101 terl::Try::<$enum_name, _>::new(p)
102 $(
103 .or_try::<Self, _>(|p| {
104 p.once_no_try::<$variant ,_>($variant::parse)
105 .map(<$enum_name>::$variant)
106 })
107 )*
108 .finish()
109 }
110 }
111 };
112}
113
114#[cfg(test)]
115mod tests {
116 use crate::parse_test;
117
118 use super::*;
119
120 #[test]
121 fn good_ident() {
122 parse_test("*)(&%^&*a(*&^%", |p| {
123 assert!(&*p.parse::<Ident>()? == "a");
124 Ok(())
125 })
126 }
127
128 #[test]
129 #[should_panic]
130 fn bad_ident() {
131 parse_test("1*)(&%^&*a(*&^%", |p| {
132 p.parse::<Ident>()?;
133 Ok(())
134 })
135 }
136}