1use std::str::FromStr;
2
3use crate::{
4 error::Error,
5 lexer::{Lexer, Token, TokenIterator},
6 syntax::*,
7};
8
9#[allow(clippy::all, reason = "generated code")]
10mod grammar {
11 include!("grammar.rs");
12}
13
14pub use crate::parser_support::ParseEntryPoint;
15use grammar::EntryPointParser;
16
17macro_rules! parse {
18 ($source:expr, $token:ident, $entrypoint:ident) => {{
19 match parse_tokens(Lexer::new($source), Token::$token) {
20 Ok(ParseEntryPoint::$entrypoint(res)) => Ok(res),
21 Ok(_) => unreachable!("parser parsed the wrong entrypoint"),
22 Err(e) => Err(e),
23 }
24 }};
25}
26
27pub fn parse_tokens(
34 lexer: impl TokenIterator,
35 entrypoint: Token,
36) -> Result<ParseEntryPoint, Error> {
37 let lexer = std::iter::once(Ok((0, entrypoint, 0))).chain(lexer);
38 let parser = EntryPointParser::new();
39 parser.parse(lexer).map_err(Into::into)
40}
41
42pub fn parse_str(source: &str) -> Result<TranslationUnit, Error> {
46 parse!(source, EntryPointTranslationUnit, TranslationUnit)
47}
48
49pub fn recognize_template_list(lexer: impl TokenIterator) -> Result<(), Error> {
50 match parse_tokens(lexer, Token::EntryPointTryTemplateList) {
51 Ok(ParseEntryPoint::TryTemplateList(_)) => Ok(()),
52 Ok(_) => unreachable!("parser parsed the wrong entrypoint"),
53 Err(e) => Err(e),
54 }
55}
56
57impl FromStr for TranslationUnit {
58 type Err = Error;
59
60 fn from_str(source: &str) -> Result<Self, Self::Err> {
61 parse!(source, EntryPointTranslationUnit, TranslationUnit)
62 }
63}
64impl FromStr for GlobalDirective {
65 type Err = Error;
66
67 fn from_str(source: &str) -> Result<Self, Self::Err> {
68 parse!(source, EntryPointGlobalDirective, GlobalDirective)
69 }
70}
71impl FromStr for GlobalDeclaration {
72 type Err = Error;
73
74 fn from_str(source: &str) -> Result<Self, Self::Err> {
75 parse!(source, EntryPointGlobalDecl, GlobalDecl)
76 }
77}
78impl FromStr for Statement {
79 type Err = Error;
80
81 fn from_str(source: &str) -> Result<Self, Self::Err> {
82 parse!(source, EntryPointStatement, Statement)
83 }
84}
85impl FromStr for Expression {
86 type Err = Error;
87
88 fn from_str(source: &str) -> Result<Self, Self::Err> {
89 parse!(source, EntryPointExpression, Expression)
90 }
91}
92impl FromStr for LiteralExpression {
93 type Err = Error;
94
95 fn from_str(source: &str) -> Result<Self, Self::Err> {
96 parse!(source, EntryPointLiteral, Literal)
97 }
98}
99impl FromStr for crate::syntax::ImportStatement {
100 type Err = Error;
101
102 fn from_str(source: &str) -> Result<Self, Self::Err> {
103 parse!(source, EntryPointImportStatement, ImportStatement)
104 }
105}
106
107#[cfg(test)]
108mod test {
109 use super::*;
110
111 fn expect_err<T: FromStr + std::fmt::Display>(expr: &str)
112 where
113 <T as FromStr>::Err: std::fmt::Debug,
114 {
115 let parsed = T::from_str(expr);
116 assert!(
117 parsed.is_err(),
118 "case `{expr}`: expected Err, got Ok({})",
119 parsed.unwrap()
120 );
121 }
122
123 fn expect_ok<T: FromStr + std::fmt::Debug>(expr: &str)
124 where
125 <T as FromStr>::Err: std::fmt::Display,
126 {
127 let parsed = T::from_str(expr);
128 assert!(
129 parsed.is_ok(),
130 "case `{expr}`: expected Ok, got Err({})",
131 parsed.unwrap_err()
132 );
133 }
134
135 #[test]
136 fn operator_prec_assoc() {
137 expect_ok::<Expression>("x & (y ^ (z | w))"); expect_ok::<Expression>("(x + y) << (z >= w)"); expect_ok::<Expression>("x < (y > z)"); expect_ok::<Expression>("x && (y || z)"); expect_err::<Expression>("x & y ^ z | w");
143 expect_err::<Expression>("x + y << z >= w");
144 expect_err::<Expression>("x < y > z");
145 expect_err::<Expression>("x && y || z");
146 expect_ok::<Expression>("x && y && z");
148 expect_ok::<Expression>("x || y || z");
149 expect_ok::<Expression>("x & y & z");
150 expect_ok::<Expression>("x ^ y ^ z");
151 expect_ok::<Expression>("x | y | z");
152 expect_err::<Expression>("x >> y >> z");
153 expect_err::<Expression>("x << y << z");
154 expect_ok::<Expression>("x && y < z && &w");
155 expect_ok::<Expression>("x & -y & &z");
156 }
157
158 #[test]
159 fn lhs_expression() {
160 expect_ok::<Statement>("(x) = 1;");
161 expect_ok::<Statement>("(*x) += 1;");
162 expect_ok::<Statement>("&(*x) += 1;");
163 expect_ok::<Statement>("x[0] = 1;");
164 expect_ok::<Statement>("x.y[0] = 1;");
165 expect_ok::<Statement>("x[0].y = 1;");
166
167 expect_ok::<Statement>("@if(true) x = 1;");
169 expect_ok::<Statement>("@if(true) &(*x) += 1;");
170 expect_err::<Statement>("@if(true) (*x) += 1;");
171 expect_ok::<Statement>("x::y = 1;");
172 }
173}