1use std::collections::HashMap;
15
16use proc_macro2::{Delimiter, LexError, Span, TokenStream, TokenTree};
17
18use crate::cursor::{Cursor, is_punct};
19use crate::error::{Error, Res, diag};
20use crate::expr::{Binding, Scope, parse_expr};
21use crate::graph::{Builder, Graph, Node};
22use crate::limits;
23
24#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct Predicate {
27 pub name: String,
29 pub params: Vec<String>,
31 pub main: Graph,
33 pub exact: Option<Graph>,
35 pub position: Position,
37 pub exact_position: Option<Position>,
39}
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43pub struct Position {
44 pub line: usize,
46 pub column: usize,
48}
49
50impl Position {
51 fn of(span: Span) -> Self {
52 let start = span.start();
53 Position {
54 line: start.line,
55 column: start.column + 1,
56 }
57 }
58}
59
60struct Form {
62 name: String,
63 name_span: Span,
64 params: Vec<String>,
65 graph: Graph,
66 exact: bool,
67}
68
69pub fn parse(source: &str, file: &str) -> Result<Vec<Predicate>, Error> {
103 parse_source(source).map_err(|d| Error {
104 file: file.to_string(),
105 line: d.line,
106 column: d.column,
107 message: d.message,
108 })
109}
110
111fn parse_source(source: &str) -> Res<Vec<Predicate>> {
112 limits::check_text(source)?;
113 let tokens: TokenStream = source
114 .parse()
115 .map_err(|e: LexError| diag(e.span(), e.to_string()))?;
116 let mut cur = Cursor::new(tokens, None);
117 let mut predicates: Vec<Predicate> = Vec::new();
118 let mut exacts: Vec<Form> = Vec::new();
119 while !cur.at_end() {
120 let form = parse_item(&mut cur)?;
121 if form.exact {
122 if exacts.iter().any(|e| e.name == form.name) {
123 return Err(diag(
124 form.name_span,
125 format!("`{}` already has an exact form", form.name),
126 ));
127 }
128 exacts.push(form);
129 } else if predicates.iter().any(|p| p.name == form.name) {
130 return Err(diag(
131 form.name_span,
132 format!("`{}` is already defined", form.name),
133 ));
134 } else {
135 predicates.push(Predicate {
136 name: form.name,
137 params: form.params,
138 main: form.graph,
139 exact: None,
140 position: Position::of(form.name_span),
141 exact_position: None,
142 });
143 }
144 }
145 for form in exacts {
146 let Some(predicate) = predicates.iter_mut().find(|p| p.name == form.name) else {
147 return Err(diag(
148 form.name_span,
149 format!("the exact form of `{}` has no main form", form.name),
150 ));
151 };
152 if predicate.params != form.params {
153 return Err(diag(
154 form.name_span,
155 format!(
156 "the exact form of `{}` must have the parameters of the main form",
157 form.name
158 ),
159 ));
160 }
161 predicate.exact = Some(form.graph);
162 predicate.exact_position = Some(Position::of(form.name_span));
163 }
164 if predicates.is_empty() {
165 return Err(diag(Span::call_site(), "no predicate definitions found"));
166 }
167 Ok(predicates)
168}
169
170fn parse_item(cur: &mut Cursor) -> Res<Form> {
172 let exact = parse_attr(cur)?;
173 if !cur.peek_word("fn") {
174 return Err(cur.expected("`fn`"));
175 }
176 cur.bump();
177 if let Some(TokenTree::Ident(id)) = cur.peek() {
178 let name = id.to_string();
179 if !can_name_a_module(&name) {
180 return Err(diag(
181 id.span(),
182 format!(
183 "`{name}` cannot be used as the name of a generated module: \
184 a predicate needs a name that is not a Rust keyword nor a raw identifier"
185 ),
186 ));
187 }
188 }
189 let (name, name_span) = parse_name(cur, "a function name")?;
190 let (params, spans) = parse_params(cur)?;
191 if !(is_punct(cur.peek(), '-') && is_punct(cur.peek_at(1), '>')) {
192 return Err(cur.expected("`->`"));
193 }
194 cur.bump();
195 cur.bump();
196 if !cur.peek_word("Sign") {
197 return Err(match cur.peek() {
198 Some(token) => diag(token.span(), "the return type must be `Sign`"),
199 None => cur.expected("`Sign`"),
200 });
201 }
202 cur.bump();
203 let (body, close) = match cur.peek() {
204 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => {
205 (g.stream(), g.span_close())
206 }
207 _ => return Err(cur.expected("`{`")),
208 };
209 cur.bump();
210 let graph = parse_body(Cursor::new(body, Some(close)), ¶ms)?;
211 for (point, (name, span)) in params.iter().zip(&spans).enumerate() {
212 let used = graph
213 .nodes
214 .iter()
215 .any(|n| matches!(n, Node::Coord { point: p, .. } if *p == point));
216 if !used {
217 return Err(diag(*span, format!("unused parameter `{name}`")));
218 }
219 }
220 Ok(Form {
221 name,
222 name_span,
223 params,
224 graph,
225 exact,
226 })
227}
228
229const KEYWORDS: [&str; 53] = [
232 "_", "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum",
233 "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move",
234 "mut", "pub", "ref", "return", "self", "Self", "static", "struct", "super", "trait", "true",
235 "type", "unsafe", "use", "where", "while", "abstract", "become", "box", "do", "final", "gen",
236 "macro", "override", "priv", "try", "typeof", "unsized", "virtual", "yield",
237];
238
239fn can_name_a_module(name: &str) -> bool {
243 !name.starts_with("r#") && !KEYWORDS.contains(&name)
244}
245
246fn parse_attr(cur: &mut Cursor) -> Res<bool> {
248 let Some(TokenTree::Punct(hash)) = cur.peek() else {
249 return Ok(false);
250 };
251 if hash.as_char() != '#' {
252 return Ok(false);
253 }
254 let span = hash.span();
255 cur.bump();
256 let is_exact = match cur.peek() {
257 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Bracket => {
258 let mut inside = Cursor::new(g.stream(), Some(g.span_close()));
259 let found = inside.peek_word("exact");
260 inside.bump();
261 found && inside.at_end()
262 }
263 _ => false,
264 };
265 if !is_exact {
266 return Err(diag(span, "the only attribute allowed is `#[exact]`"));
267 }
268 cur.bump();
269 if is_punct(cur.peek(), '#') {
270 return Err(diag(
271 cur.peek().map_or(span, TokenTree::span),
272 "the only attribute allowed is a single `#[exact]`",
273 ));
274 }
275 Ok(true)
276}
277
278fn parse_name(cur: &mut Cursor, what: &str) -> Res<(String, Span)> {
280 match cur.peek() {
281 Some(TokenTree::Ident(id)) if id != "fn" && id != "let" => {
282 let result = (id.to_string(), id.span());
283 cur.bump();
284 Ok(result)
285 }
286 _ => Err(cur.expected(what)),
287 }
288}
289
290fn parse_params(cur: &mut Cursor) -> Res<(Vec<String>, Vec<Span>)> {
292 let (stream, close) = match cur.peek() {
293 Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => {
294 (g.stream(), g.span_close())
295 }
296 _ => return Err(cur.expected("`(`")),
297 };
298 cur.bump();
299 let mut inside = Cursor::new(stream, Some(close));
300 let (mut names, mut spans): (Vec<String>, Vec<Span>) = (Vec::new(), Vec::new());
301 while !inside.at_end() {
302 let (name, span) = parse_name(&mut inside, "a parameter name")?;
303 if names.contains(&name) {
304 return Err(diag(span, format!("`{name}` redefines a name")));
305 }
306 if !inside.peek_punct(':') {
307 return Err(inside.expected("`:`"));
308 }
309 inside.bump();
310 match inside.peek() {
311 Some(TokenTree::Ident(id)) if id == "Point3" => inside.bump(),
312 Some(token) => {
313 return Err(diag(token.span(), "a parameter must have type `Point3`"));
314 }
315 None => return Err(inside.expected("the type `Point3`")),
316 }
317 names.push(name);
318 spans.push(span);
319 if !inside.at_end() {
320 if !inside.peek_punct(',') {
321 return Err(inside.expected("`,`"));
322 }
323 inside.bump();
324 }
325 }
326 Ok((names, spans))
327}
328
329fn parse_body(mut body: Cursor, params: &[String]) -> Res<Graph> {
331 let mut env: HashMap<String, Binding> = params
332 .iter()
333 .enumerate()
334 .map(|(i, name)| (name.clone(), Binding::Param(i)))
335 .collect();
336 let mut builder = Builder::default();
337 loop {
338 if body.at_end() {
339 return Err(diag(body.close(), "the body needs a final expression"));
340 }
341 if !body.peek_word("let") {
342 let mut scope = Scope {
343 builder: &mut builder,
344 env: &env,
345 };
346 let root = parse_expr(&mut body, &mut scope, 1)?;
347 if let Some(token) = body.peek() {
348 return Err(if is_punct(Some(token), ';') {
349 diag(
350 token.span(),
351 "expected `let` bindings followed by a final expression without `;`",
352 )
353 } else {
354 body.expected("an operator or the end of the body")
355 });
356 }
357 return Ok(builder.finish(root));
358 }
359 body.bump();
360 let (name, span) = parse_name(&mut body, "a name")?;
361 if env.contains_key(&name) {
362 return Err(diag(span, format!("`{name}` redefines a name")));
363 }
364 if !body.peek_punct('=') {
365 return Err(body.expected("`=`"));
366 }
367 body.bump();
368 let mut scope = Scope {
369 builder: &mut builder,
370 env: &env,
371 };
372 let value = parse_expr(&mut body, &mut scope, 1)?;
373 if !body.peek_punct(';') {
374 return Err(body.expected("an operator or `;`"));
375 }
376 body.bump();
377 env.insert(name, Binding::Let(value));
378 }
379}