rune/indexing/
index2.rs

1use core::mem::replace;
2
3use crate::alloc;
4use crate::alloc::prelude::*;
5use crate::ast::{self, Kind, Span, Spanned};
6use crate::compile::{
7    meta, Doc, DynLocation, Error, ErrorKind, Location, Result, Visibility, WithSpan,
8};
9use crate::grammar::{Ignore, MaybeNode, Node, NodeId, Remaining, Stream, StreamBuf};
10use crate::indexing;
11use crate::parse::Resolve;
12use crate::query::{Attrs, BuiltInLiteral, DeferEntry, ExpandMacroBuiltin, ImplItem, ImplItemKind};
13use crate::runtime::Call;
14use crate::worker::{self, Import, ImportKind, ImportState};
15
16use super::items::Guard;
17use super::{validate_call, IndexItem, Indexed, Indexer};
18
19use Kind::*;
20
21/// The kind of an [ExprBlock].
22#[derive(Debug, Clone, Copy, PartialEq)]
23#[non_exhaustive]
24pub(crate) enum ExprBlockKind {
25    Default,
26    Async,
27    Const,
28}
29
30#[derive(Default, Debug)]
31enum ExprSupport {
32    Yes,
33    #[default]
34    No,
35}
36
37struct Function<'a> {
38    node: Node<'a>,
39    name: Option<ast::Ident>,
40    attrs: Attrs,
41    mods: Mods,
42}
43
44fn is_instance(node: &Node<'_>) -> alloc::Result<(bool, Vec<Span>)> {
45    fn is_self(node: Node<'_>) -> bool {
46        let Some([node]) = node.nodes::<1>() else {
47            return false;
48        };
49
50        matches!(
51            (node.kind(), node.kinds()),
52            (IndexedPath(..), Some([K![self]]))
53        )
54    }
55
56    let mut is_instance = false;
57    let mut args = Vec::new();
58
59    let Some(node) = node.find(FnArgs) else {
60        return Ok((is_instance, args));
61    };
62
63    for node in node.children() {
64        if matches!(node.kind(), Pat) {
65            args.try_push(node.span())?;
66            is_instance |= is_self(node);
67        }
68    }
69
70    Ok((is_instance, args))
71}
72
73/// Indexing event.
74#[derive(Debug)]
75enum State<'a> {
76    Stream(StreamBuf<'a>),
77    Expr(Mods, Attrs),
78    Block(Guard, IndexItem),
79    ConstBlock(Guard, IndexItem, Node<'a>),
80    AsyncBlock(Guard, IndexItem, Span, Option<ast::Move>),
81    Bare(IndexItem, NodeId),
82    Function(Guard, IndexItem, usize, Option<Span>, ExprSupport),
83    Module(Guard, IndexItem),
84    Closure(Guard, IndexItem, Option<ast::Async>, Option<ast::Move>),
85    Const(Guard, IndexItem, Option<Span>, Node<'a>, ExprSupport),
86}
87
88struct Processor<'a> {
89    span: Span,
90    fns: Vec<Function<'a>>,
91    stack: Vec<State<'a>>,
92    expr: ExprSupport,
93}
94
95impl<'a> Processor<'a> {
96    fn new(span: Span) -> Self {
97        Self {
98            span,
99            fns: Vec::new(),
100            stack: Vec::new(),
101            expr: ExprSupport::No,
102        }
103    }
104
105    fn with_expr(mut self, expr: ExprSupport) -> Self {
106        self.expr = expr;
107        self
108    }
109
110    fn process(mut self, idx: &mut Indexer<'_, '_>) -> Result<()> {
111        loop {
112            if let Some(State::Stream(p)) = self.stack.last_mut() {
113                let Some(node) = p.next() else {
114                    self.stack.pop();
115                    continue;
116                };
117
118                tracing::trace!(?node, stack = self.stack.len());
119                self.node(idx, node)?;
120                continue;
121            };
122
123            let Some(state) = self.stack.pop() else {
124                break;
125            };
126
127            tracing::trace!(?state, stack = self.stack.len());
128
129            match state {
130                State::Expr(mods, attrs) => {
131                    mods.deny_all(idx)?;
132                    attrs.deny_any(idx)?;
133                }
134                State::Block(guard, item) => {
135                    idx.item = item;
136                    idx.items.pop(guard).with_span(self.span)?;
137                }
138                State::AsyncBlock(guard, item, span, move_token) => {
139                    let item_meta = idx
140                        .q
141                        .item_for("async block", idx.item.id)
142                        .with_span(self.span)?;
143                    let layer = idx.scopes.pop().with_span(self.span)?;
144                    let call = validate_call(false, true, &layer)?;
145
146                    if let Some(call) = call {
147                        idx.q.index_meta(
148                            &span,
149                            item_meta,
150                            meta::Kind::AsyncBlock {
151                                call,
152                                do_move: move_token.is_some(),
153                            },
154                        )?;
155                    } else {
156                        idx.error(Error::new(span, ErrorKind::ClosureKind))?;
157                    }
158
159                    idx.item = item;
160                    idx.items.pop(guard).with_span(self.span)?;
161                }
162                State::ConstBlock(guard, item, node) => {
163                    let item_meta = idx
164                        .q
165                        .item_for("const block", idx.item.id)
166                        .with_span(self.span)?;
167
168                    idx.q.index_const_block(
169                        item_meta,
170                        indexing::ConstBlock::Node(node.node_at(idx.source_id, idx.tree.clone())),
171                    )?;
172
173                    idx.item = item;
174                    idx.items.pop(guard).with_span(self.span)?;
175                }
176                State::Closure(guard, item, async_token, move_token) => {
177                    let layer = idx.scopes.pop().with_span(self.span)?;
178                    let call = validate_call(false, async_token.is_some(), &layer)?;
179
180                    let Some(call) = call else {
181                        return Err(Error::new(self.span, ErrorKind::ClosureKind));
182                    };
183
184                    let item_meta = idx
185                        .q
186                        .item_for("closure", idx.item.id)
187                        .with_span(self.span)?;
188
189                    idx.q.index_meta(
190                        &self.span,
191                        item_meta,
192                        meta::Kind::Closure {
193                            call,
194                            do_move: move_token.is_some(),
195                        },
196                    )?;
197
198                    idx.item = item;
199                    idx.items.pop(guard).with_span(self.span)?;
200                }
201                State::Bare(item, id) => {
202                    self.bare(idx, id)?;
203
204                    idx.item = item;
205                }
206                State::Function(guard, item, index, nested_item, expr) => {
207                    self.function(idx, index, nested_item)?;
208
209                    self.expr = expr;
210
211                    idx.item = item;
212                    idx.items.pop(guard).with_span(self.span)?;
213                    idx.nested_item = nested_item;
214                }
215                State::Module(guard, item) => {
216                    idx.item = item;
217                    idx.items.pop(guard).with_span(self.span)?;
218                }
219                State::Const(guard, idx_item, nested_item, node, expr) => {
220                    let item_meta = idx.q.item_for("const", idx.item.id).with_span(self.span)?;
221
222                    idx.q.index_const_expr(
223                        item_meta,
224                        indexing::ConstExpr::Node(node.node_at(idx.source_id, idx.tree.clone())),
225                    )?;
226
227                    self.expr = expr;
228
229                    idx.items.pop(guard).with_span(&node)?;
230                    idx.item = idx_item;
231                    idx.nested_item = nested_item;
232                }
233                State::Stream(..) => {}
234            }
235        }
236
237        Ok(())
238    }
239
240    fn node(&mut self, idx: &mut Indexer<'_, '_>, node: Node<'a>) -> Result<()> {
241        self.span = node.span();
242
243        match node.kind() {
244            Expr => {
245                if matches!(self.expr, ExprSupport::No) {
246                    idx.error(Error::msg(
247                        &node,
248                        "expression is not supported during indexing",
249                    ))?;
250                    return Ok(());
251                }
252
253                let (mods, attrs, p) = node.parse(|p| {
254                    let mods = p
255                        .eat(Modifiers)
256                        .parse(|p| Mods::parse(idx, p))?
257                        .unwrap_or_default();
258                    let attrs = attributes(idx, p)?;
259                    Ok((mods, attrs, p.take_remaining()))
260                })?;
261
262                self.stack.try_push(State::Expr(mods, attrs))?;
263                self.stack.try_push(State::Stream(p))?;
264                return Ok(());
265            }
266            ExprMacroCall => {
267                let builtin;
268
269                if let [.., State::Expr(_, attrs), _] = &mut self.stack[..] {
270                    builtin = attrs.builtin.take();
271                } else {
272                    builtin = None;
273                }
274
275                let (literal, is_builtin) = match builtin {
276                    Some((_, literal)) => (literal, true),
277                    _ => (BuiltInLiteral::No, false),
278                };
279
280                let call = |id| {
281                    Ok::<_, alloc::Error>(ExpandMacroBuiltin {
282                        id,
283                        node: node.node_at(idx.source_id, idx.tree.clone()),
284                        location: Location::new(idx.source_id, node.span()),
285                        root: idx.root.map(TryToOwned::try_to_owned).transpose()?,
286                        macro_depth: idx.macro_depth,
287                        item: idx.item,
288                        literal,
289                    })
290                };
291
292                let id = if is_builtin {
293                    idx.q
294                        .insert_new_macro(move |id| Ok(DeferEntry::ExpandMacroBuiltin(call(id)?)))
295                        .with_span(self.span)?
296                } else {
297                    for node in node.children() {
298                        if node.kind() == Path {
299                            node.replace(IndexedPath(idx.item.id));
300                        }
301                    }
302
303                    idx.q
304                        .insert_new_macro(move |id| Ok(DeferEntry::ExpandMacroCall(call(id)?)))
305                        .with_span(self.span)?
306                };
307
308                node.replace(ExpandedMacro(id));
309                return Ok(());
310            }
311            ExprClosure => {
312                let async_token;
313                let move_token;
314
315                if let [.., State::Expr(mods, _), _] = &mut self.stack[..] {
316                    async_token = mods.async_token.take();
317                    move_token = mods.move_token.take();
318                } else {
319                    async_token = None;
320                    move_token = None;
321                }
322
323                let guard = idx.push_id()?;
324                idx.scopes.push()?;
325                let item_meta = idx.insert_new_item(&self.span, Visibility::Inherited, &[])?;
326                let item = idx.item.replace(item_meta.item);
327                self.stack
328                    .try_push(State::Closure(guard, item, async_token, move_token))?;
329                node.replace(Closure(idx.item.id));
330            }
331            Path => {
332                node.replace(IndexedPath(idx.item.id));
333            }
334            Block => {
335                let async_token;
336                let const_token;
337                let move_token;
338
339                if let [.., State::Expr(mods, _), _] = &mut self.stack[..] {
340                    async_token = mods.async_token.take();
341                    const_token = mods.const_token.take();
342                    move_token = mods.move_token.take();
343                } else {
344                    async_token = None;
345                    const_token = None;
346                    move_token = None;
347                }
348
349                let guard = idx.push_id()?;
350                let item_meta = idx.insert_new_item(&self.span, Visibility::Inherited, &[])?;
351                let item = idx.item.replace(item_meta.item);
352
353                let kind = match (async_token, const_token) {
354                    (Some(const_token), Some(async_token)) => {
355                        idx.error(Error::new(
356                            const_token.span.join(async_token.span),
357                            ErrorKind::FnConstAsyncConflict,
358                        ))?;
359
360                        ExprBlockKind::Default
361                    }
362                    (Some(..), None) => ExprBlockKind::Async,
363                    (None, Some(..)) => ExprBlockKind::Const,
364                    _ => ExprBlockKind::Default,
365                };
366
367                match kind {
368                    ExprBlockKind::Default => {
369                        self.stack.try_push(State::Block(guard, item))?;
370                    }
371                    ExprBlockKind::Const => {
372                        self.stack
373                            .try_push(State::ConstBlock(guard, item, node.clone()))?;
374                        node.replace(ConstBlock(idx.item.id));
375                    }
376                    ExprBlockKind::Async => {
377                        idx.scopes.push()?;
378                        self.stack.try_push(State::AsyncBlock(
379                            guard,
380                            item,
381                            node.span(),
382                            move_token,
383                        ))?;
384                        node.replace(AsyncBlock(idx.item.id));
385                    }
386                }
387            }
388            ExprSelect | ExprAwait => {
389                let l = idx.scopes.mark().with_span(self.span)?;
390                l.awaits.try_push(node.span())?;
391            }
392            ExprYield => {
393                let l = idx.scopes.mark().with_span(self.span)?;
394                l.yields.try_push(node.span())?;
395            }
396            Item => {
397                let result = node.parse(|p| {
398                    let attrs = attributes(idx, p)?;
399                    p.pump()?.parse(|p| self.item(idx, p, attrs))?;
400                    Ok(())
401                });
402
403                if let Err(error) = result {
404                    idx.error(error)?;
405                }
406
407                return Ok(());
408            }
409            _ => {}
410        }
411
412        let mut p = node.into_stream();
413
414        if !p.is_eof() {
415            self.stack.try_push(State::Stream(p)).with_span(self.span)?;
416        }
417
418        Ok(())
419    }
420
421    fn bare(&mut self, idx: &mut Indexer<'_, '_>, id: NodeId) -> Result<()> {
422        let item_meta = idx
423            .q
424            .item_for("bare function", idx.item.id)
425            .with_span(self.span)?;
426        let layer = idx.scopes.pop().with_span(self.span)?;
427
428        let call = match (layer.awaits.is_empty(), layer.yields.is_empty()) {
429            (true, true) => Call::Immediate,
430            (false, true) => Call::Async,
431            (true, false) => Call::Generator,
432            (false, false) => Call::Stream,
433        };
434
435        idx.q.index_and_build(indexing::Entry {
436            item_meta,
437            indexed: Indexed::Function(indexing::Function {
438                ast: indexing::FunctionAst::Bare(idx.tree.node_at(idx.source_id, id)),
439                call,
440                is_instance: false,
441                is_test: false,
442                is_bench: false,
443                impl_item: None,
444                args: Vec::new(),
445            }),
446        })?;
447
448        Ok(())
449    }
450
451    fn function(
452        &mut self,
453        idx: &mut Indexer<'_, '_>,
454        index: usize,
455        nested_item: Option<Span>,
456    ) -> Result<(), Error> {
457        let Some(f) = self.fns.pop() else {
458            return Err(Error::msg(self.span, "missing function being indexed"));
459        };
460
461        if index != self.fns.len() {
462            return Err(Error::msg(self.span, "function indexing mismatch"));
463        }
464
465        let item_meta = idx
466            .q
467            .item_for("function", idx.item.id)
468            .with_span(self.span)?;
469
470        let Function {
471            node,
472            name,
473            attrs,
474            mods,
475        } = f;
476
477        self.span = node.span();
478
479        let (is_instance, args) = is_instance(&node).with_span(&node)?;
480        let layer = idx.scopes.pop().with_span(self.span)?;
481
482        if let (Some(const_token), Some(async_token)) = (mods.const_token, mods.async_token) {
483            idx.error(Error::new(
484                const_token.span.join(async_token.span),
485                ErrorKind::FnConstAsyncConflict,
486            ))?;
487        };
488
489        let call = validate_call(
490            mods.const_token.is_some(),
491            mods.async_token.is_some(),
492            &layer,
493        )?;
494
495        let Some(call) = call else {
496            idx.q.index_const_fn(
497                item_meta,
498                indexing::ConstFn::Node(node.node_at(idx.source_id, idx.tree.clone())),
499            )?;
500            return Ok(());
501        };
502
503        if let (Some(span), Some(_nested_span)) = (attrs.test, nested_item) {
504            idx.error(Error::new(
505                span,
506                ErrorKind::NestedTest {
507                    #[cfg(feature = "emit")]
508                    nested_span: _nested_span,
509                },
510            ))?;
511        }
512
513        if let (Some(span), Some(_nested_span)) = (attrs.bench, nested_item) {
514            idx.error(Error::new(
515                span,
516                ErrorKind::NestedBench {
517                    #[cfg(feature = "emit")]
518                    nested_span: _nested_span,
519                },
520            ))?;
521        }
522
523        let is_test = attrs.test.is_some();
524        let is_bench = attrs.bench.is_some();
525
526        if idx.item.impl_item.is_some() {
527            if is_test {
528                idx.error(Error::msg(
529                    &node,
530                    "the #[test] attribute is not supported on associated functions",
531                ))?;
532            }
533
534            if is_bench {
535                idx.error(Error::msg(
536                    &node,
537                    "the #[bench] attribute is not supported on associated functions",
538                ))?;
539            }
540        }
541
542        if is_instance && idx.item.impl_item.is_none() {
543            idx.error(Error::new(&node, ErrorKind::InstanceFunctionOutsideImpl))?;
544        };
545
546        let entry = indexing::Entry {
547            item_meta,
548            indexed: Indexed::Function(indexing::Function {
549                ast: indexing::FunctionAst::Node(
550                    node.node_at(idx.source_id, idx.tree.clone()),
551                    name,
552                ),
553                call,
554                is_instance,
555                is_test,
556                is_bench,
557                impl_item: idx.item.impl_item,
558                args,
559            }),
560        };
561
562        let is_exported = is_instance
563            || item_meta.is_public(idx.q.pool) && nested_item.is_none()
564            || is_test
565            || is_bench;
566
567        if is_exported {
568            idx.q.index_and_build(entry)?;
569        } else {
570            idx.q.index(entry)?;
571        }
572
573        Ok(())
574    }
575
576    fn item(&mut self, idx: &mut Indexer<'_, '_>, p: &mut Stream<'a>, attrs: Attrs) -> Result<()> {
577        let mods = p
578            .eat(Modifiers)
579            .parse(|p| Mods::parse(idx, p))?
580            .unwrap_or_default();
581
582        match p.kind() {
583            ItemFn => {
584                self.item_fn(idx, p, mods, attrs)?;
585            }
586            ItemMod => {
587                self.item_mod(idx, p, mods, attrs)?;
588            }
589            ItemFileMod => {
590                self.item_file_mod(idx, p, mods, attrs)?;
591            }
592            ItemImpl => {
593                item_impl(idx, p, mods, attrs)?;
594            }
595            ItemStruct => {
596                item_struct(idx, p, mods, attrs)?;
597            }
598            ItemEnum => {
599                item_enum(idx, p, mods, attrs)?;
600            }
601            ItemConst => {
602                self.item_const(idx, p, mods, attrs)?;
603            }
604            ItemUse => {
605                item_use(idx, p, mods, attrs)?;
606            }
607            _ => {
608                idx.error(p.expected("item"))?;
609                p.ignore();
610            }
611        }
612
613        Ok(())
614    }
615
616    fn item_fn(
617        &mut self,
618        idx: &mut Indexer<'_, '_>,
619        p: &mut Stream<'a>,
620        mods: Mods,
621        attrs: Attrs,
622    ) -> Result<(), Error> {
623        let expr = replace(&mut self.expr, ExprSupport::Yes);
624
625        p.expect(K![fn])?;
626
627        let (guard, name) = push_name(idx, p, "function")?;
628        let item_meta = idx.insert_new_item(&*p, mods.visibility, &attrs.docs)?;
629        let item = idx.item.replace(item_meta.item);
630        idx.scopes.push()?;
631
632        let nested_item = idx.nested_item.replace(p.span());
633        let index = self.fns.len();
634
635        self.fns.try_push(Function {
636            node: p.node(),
637            name,
638            attrs,
639            mods,
640        })?;
641
642        self.stack
643            .try_push(State::Function(guard, item, index, nested_item, expr))?;
644        self.stack.try_push(State::Stream(p.take_remaining()))?;
645        Ok(())
646    }
647
648    fn item_mod(
649        &mut self,
650        idx: &mut Indexer<'_, '_>,
651        p: &mut Stream<'a>,
652        mut mods: Mods,
653        attrs: Attrs,
654    ) -> Result<()> {
655        p.expect(K![mod])?;
656        let (guard, _) = push_name(idx, p, "module")?;
657
658        let MaybeNode::Some(node) = p.eat(Block) else {
659            idx.error(p.expected_peek(Block))?;
660            return Ok(());
661        };
662
663        let (mod_item, mod_item_id) = idx.q.insert_mod(
664            &idx.items,
665            &DynLocation::new(idx.source_id, &*p),
666            idx.item.module,
667            mods.visibility.take(),
668            &attrs.docs,
669        )?;
670
671        let item = idx.item.replace_module(mod_item, mod_item_id);
672
673        self.stack.try_push(State::Module(guard, item))?;
674        self.stack.try_push(State::Stream(node.into_stream()))?;
675
676        mods.deny_all(idx)?;
677        attrs.deny_non_docs(idx)?;
678        Ok(())
679    }
680
681    fn item_file_mod(
682        &mut self,
683        idx: &mut Indexer<'_, '_>,
684        p: &mut Stream<'_>,
685        mut mods: Mods,
686        attrs: Attrs,
687    ) -> Result<()> {
688        p.expect(K![mod])?;
689        let (guard, _) = push_name(idx, p, "module")?;
690
691        let (mod_item, mod_item_id) = idx.q.insert_mod(
692            &idx.items,
693            &DynLocation::new(idx.source_id, &*p),
694            idx.item.module,
695            mods.visibility.take(),
696            &attrs.docs,
697        )?;
698
699        idx.items.pop(guard).with_span(&*p)?;
700
701        let Some(root) = idx.root else {
702            return Err(Error::new(&*p, ErrorKind::UnsupportedModuleSource));
703        };
704
705        let source = idx
706            .q
707            .source_loader
708            .load(root, idx.q.pool.module_item(mod_item), &*p)?;
709
710        if let Some(loaded) = idx.loaded.as_mut() {
711            if let Some(_existing) = loaded.try_insert(mod_item, (idx.source_id, p.span()))? {
712                return Err(Error::new(
713                    &*p,
714                    ErrorKind::ModAlreadyLoaded {
715                        item: idx.q.pool.module_item(mod_item).try_to_owned()?,
716                        #[cfg(feature = "emit")]
717                        existing: _existing,
718                    },
719                ));
720            }
721        }
722
723        let source_id = idx.q.sources.insert(source)?;
724
725        idx.q
726            .visitor
727            .visit_mod(&DynLocation::new(source_id, &*p))
728            .with_span(&*p)?;
729
730        if let Some(queue) = idx.queue.as_mut() {
731            queue.try_push_back(worker::Task::LoadFile {
732                kind: worker::LoadFileKind::Module {
733                    root: idx.root.map(|p| p.try_to_owned()).transpose()?,
734                },
735                source_id,
736                mod_item,
737                mod_item_id,
738            })?;
739        }
740
741        mods.deny_all(idx)?;
742        attrs.deny_non_docs(idx)?;
743        Ok(())
744    }
745
746    fn item_const(
747        &mut self,
748        idx: &mut Indexer<'_, '_>,
749        p: &mut Stream<'a>,
750        mut mods: Mods,
751        attrs: Attrs,
752    ) -> Result<()> {
753        let expr = replace(&mut self.expr, ExprSupport::Yes);
754
755        if mods.const_token.take().is_none() {
756            idx.error(Error::msg(&*p, "missing `const` modifier"))?;
757        }
758
759        let (guard, _) = push_name(idx, p, "constant")?;
760
761        p.expect(K![=])?;
762        let value = p.expect(Expr)?;
763
764        let item_meta = idx.insert_new_item(&value, mods.visibility.take(), &attrs.docs)?;
765
766        let idx_item = idx.item.replace(item_meta.item);
767        let last = idx.nested_item.replace(value.span());
768
769        self.stack
770            .try_push(State::Const(guard, idx_item, last, value.clone(), expr))?;
771
772        self.stack.try_push(State::Stream(value.into_stream()))?;
773
774        mods.deny_all(idx)?;
775        attrs.deny_non_docs(idx)?;
776        Ok(())
777    }
778}
779
780/// Index the contents of a module known by its AST as a "file".
781pub(crate) fn bare(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<()> {
782    let item_meta = idx.insert_new_item(p, Visibility::Public, &[])?;
783    let item = idx.item.replace(item_meta.item);
784
785    idx.scopes.push()?;
786
787    inner_attributes(idx, p)?;
788
789    let mut proc = Processor::new(p.span()).with_expr(ExprSupport::Yes);
790    proc.stack.try_push(State::Bare(item, p.id()))?;
791    proc.stack.try_push(State::Stream(p.take_remaining()))?;
792    proc.process(idx)?;
793    Ok(())
794}
795
796/// Index the contents of a module known by its AST as a "file".
797pub(crate) fn file(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<()> {
798    inner_attributes(idx, p)?;
799
800    let mut proc = Processor::new(p.span());
801    proc.stack.try_push(State::Stream(p.take_remaining()))?;
802    proc.process(idx)?;
803    Ok(())
804}
805
806/// Index an item.
807pub(crate) fn item(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>, attrs: Attrs) -> Result<()> {
808    let mut proc = Processor::new(p.span());
809    proc.item(idx, p, attrs)?;
810    proc.process(idx)?;
811    Ok(())
812}
813
814/// Index anything.
815pub(crate) fn any(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<()> {
816    let mut proc = Processor::new(p.span()).with_expr(ExprSupport::Yes);
817    proc.stack.try_push(State::Stream(p.take_remaining()))?;
818    proc.process(idx)?;
819    Ok(())
820}
821
822fn item_impl(
823    idx: &mut Indexer<'_, '_>,
824    p: &mut Stream<'_>,
825    mods: Mods,
826    attrs: Attrs,
827) -> Result<()> {
828    p.expect(K![impl])?;
829
830    let MaybeNode::Some(node) = p.eat(Path) else {
831        idx.error(p.expected_peek(Path))?;
832        return Ok(());
833    };
834
835    node.replace(IndexedPath(idx.item.id));
836
837    let mut functions = Vec::new();
838
839    p.eat(Block).parse(|p| {
840        p.eat(K!['{']);
841
842        p.expect(BlockBody)?.parse(|p| {
843            while let MaybeNode::Some(item) = p.eat(Item) {
844                item.parse(|p| {
845                    let attrs = attributes(idx, p)?;
846
847                    p.pump()?.parse(|p| {
848                        let mods = p
849                            .eat(Modifiers)
850                            .parse(|p| Mods::parse(idx, p))?
851                            .unwrap_or_default();
852
853                        mods.deny_all(idx)?;
854
855                        match p.kind() {
856                            ItemFn => {
857                                functions.try_push((p.id(), attrs)).with_span(&*p)?;
858                                p.ignore();
859                            }
860                            _ => {
861                                idx.error(p.expected(ItemFn)).with_span(&*p)?;
862                            }
863                        }
864
865                        Ok(())
866                    })?;
867
868                    Ok(())
869                })?;
870            }
871
872            Ok(())
873        })?;
874
875        p.eat(K!['}']);
876        Ok(())
877    })?;
878
879    let location = Location::new(idx.source_id, p.span());
880
881    idx.q
882        .inner
883        .defer_queue
884        .try_push_back(DeferEntry::ImplItem(ImplItem {
885            kind: ImplItemKind::Node {
886                path: node.node_at(idx.source_id, idx.tree.clone()),
887                functions,
888            },
889            location,
890            root: idx.root.map(TryToOwned::try_to_owned).transpose()?,
891            nested_item: idx.nested_item,
892            macro_depth: idx.macro_depth,
893        }))?;
894
895    mods.deny_all(idx)?;
896    attrs.deny_non_docs(idx)?;
897    Ok(())
898}
899
900fn item_struct(
901    idx: &mut Indexer<'_, '_>,
902    p: &mut Stream<'_>,
903    mut mods: Mods,
904    attrs: Attrs,
905) -> Result<()> {
906    p.expect(K![struct])?;
907    let (guard, _) = push_name(idx, p, "struct")?;
908
909    let item_meta = idx.insert_new_item(&*p, mods.visibility.take(), &attrs.docs)?;
910
911    let fields = p.pump()?.parse(|p| fields(idx, p))?;
912
913    idx.q.index_struct(item_meta, indexing::Struct { fields })?;
914
915    idx.items.pop(guard).with_span(&*p)?;
916
917    mods.deny_all(idx)?;
918    attrs.deny_non_docs(idx)?;
919    Ok(())
920}
921
922fn item_enum(
923    idx: &mut Indexer<'_, '_>,
924    p: &mut Stream<'_>,
925    mut mods: Mods,
926    attrs: Attrs,
927) -> Result<()> {
928    p.expect(K![enum])?;
929    let (guard, _) = push_name(idx, p, "enum")?;
930
931    let vis = mods.visibility.take();
932
933    let enum_item_meta = idx.insert_new_item(&*p, vis, &attrs.docs)?;
934
935    idx.q.index_enum(enum_item_meta)?;
936
937    p.eat(K!['{']);
938
939    let mut comma = Remaining::default();
940
941    while let MaybeNode::Some(node) = p.eat(Variant) {
942        comma.at_most_one(idx)?;
943
944        let (item_meta, fields, attrs) = node.parse(|p| {
945            let attrs = attributes(idx, p)?;
946
947            let (guard, _) = push_name(idx, p, "variant")?;
948            let item_meta = idx.insert_new_item(&*p, vis, &attrs.docs)?;
949            let fields = p.pump()?.parse(|p| fields(idx, p))?;
950            idx.items.pop(guard).with_span(&*p)?;
951
952            Ok((item_meta, fields, attrs))
953        })?;
954
955        attrs.deny_non_docs(idx)?;
956
957        let variant = indexing::Variant {
958            enum_id: enum_item_meta.item,
959            fields,
960        };
961
962        idx.q.index_variant(item_meta, variant)?;
963
964        comma = p.remaining(idx, K![,])?;
965    }
966
967    comma.at_most_one(idx)?;
968    p.eat(K!['}']);
969    idx.items.pop(guard).with_span(&*p)?;
970
971    mods.deny_all(idx)?;
972    attrs.deny_non_docs(idx)?;
973    Ok(())
974}
975
976fn item_use(
977    idx: &mut Indexer<'_, '_>,
978    p: &mut Stream<'_>,
979    mut mods: Mods,
980    attrs: Attrs,
981) -> Result<()> {
982    let import = Import {
983        state: ImportState::Node(p.node().node_at(idx.source_id, idx.tree.clone())),
984        kind: ImportKind::Global,
985        visibility: mods.visibility.take(),
986        module: idx.item.module,
987        item: idx.items.item().try_to_owned()?,
988        source_id: idx.source_id,
989    };
990
991    let span = p.span();
992
993    import.process(&mut idx.q, &mut |task| {
994        let Some(queue) = &mut idx.queue else {
995            return Err(Error::msg(
996                span,
997                "deferred imports are not supported in this context",
998            ));
999        };
1000
1001        queue.try_push_back(task)?;
1002        Ok(())
1003    })?;
1004
1005    // Ignore remaining tokens since they will be processed by the
1006    // import.
1007    p.ignore();
1008
1009    mods.deny_all(idx)?;
1010    attrs.deny_any(idx)?;
1011    Ok(())
1012}
1013
1014fn push_name(
1015    idx: &mut Indexer<'_, '_>,
1016    p: &mut Stream<'_>,
1017    what: &'static str,
1018) -> Result<(Guard, Option<ast::Ident>)> {
1019    let (guard, ident) = if let Some(ident) = p.try_ast::<ast::Ident>()? {
1020        let name = ident.resolve(resolve_context!(idx.q))?;
1021        (idx.items.push_name(name.as_ref())?, Some(ident))
1022    } else {
1023        idx.error(Error::msg(
1024            p.peek_span().head(),
1025            try_format!("expected {what} name"),
1026        ))?;
1027        (idx.push_id()?, None)
1028    };
1029
1030    Ok((guard, ident))
1031}
1032
1033fn attributes(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<Attrs> {
1034    let mut attrs = Attrs::default();
1035
1036    while let MaybeNode::Some(node) = p.eat(Attribute) {
1037        node.parse(|p| {
1038            let span = p.span();
1039
1040            p.all([K![#], K!['[']])?;
1041
1042            p.expect(TokenStream)?.parse(|p| {
1043                let ident = p.ast::<ast::Ident>()?;
1044
1045                match ident.resolve(resolve_context!(idx.q))? {
1046                    "test" => {
1047                        if attrs.bench.is_some() {
1048                            idx.error(Error::msg(ident.span, "duplicate #[test] attribute"))?;
1049                        } else {
1050                            attrs.test = Some(ident.span);
1051                        }
1052                    }
1053                    "bench" => {
1054                        if attrs.bench.is_some() {
1055                            idx.error(Error::msg(ident.span, "duplicate #[bench] attribute"))?;
1056                        } else {
1057                            attrs.bench = Some(ident.span);
1058                        }
1059                    }
1060                    "doc" => {
1061                        p.expect(K![=])?;
1062                        let doc_string = p.ast::<ast::LitStr>()?;
1063                        attrs
1064                            .docs
1065                            .try_push(Doc { span, doc_string })
1066                            .with_span(&*p)?;
1067                    }
1068                    "builtin" => {
1069                        let mut literal = BuiltInLiteral::No;
1070
1071                        if p.eat(K!['(']).is_some() {
1072                            while matches!(p.peek(), K![ident]) {
1073                                let ident = p.ast::<ast::Ident>()?;
1074
1075                                match ident.resolve(resolve_context!(idx.q))? {
1076                                    "literal" => {
1077                                        literal = BuiltInLiteral::Yes(ident.span());
1078                                    }
1079                                    other => {
1080                                        idx.error(Error::msg(
1081                                            ident,
1082                                            try_format!("unsupported builtin option `{other}`"),
1083                                        ))?;
1084                                    }
1085                                }
1086
1087                                p.remaining(idx, K![,])?.ignore(idx)?;
1088                            }
1089
1090                            p.expect(K![')'])?;
1091                        }
1092
1093                        if attrs.builtin.is_some() {
1094                            idx.error(Error::msg(ident.span, "duplicate #[builtin] attribute"))?;
1095                        } else {
1096                            attrs.builtin = Some((ident.span, literal));
1097                        }
1098                    }
1099                    name => {
1100                        idx.error(Error::msg(
1101                            ident,
1102                            try_format!("unsupported attribute `{name}`"),
1103                        ))?;
1104                    }
1105                }
1106
1107                Ok(())
1108            })?;
1109
1110            p.expect(K![']'])?;
1111            Ok(())
1112        })?;
1113    }
1114
1115    Ok(attrs)
1116}
1117
1118fn inner_attributes(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<()> {
1119    while let MaybeNode::Some(node) = p.eat(InnerAttribute) {
1120        node.parse(|p| {
1121            p.all([K![#], K![!], K!['[']])?;
1122
1123            p.expect(TokenStream)?.parse(|p| {
1124                let ident = p.ast::<ast::Ident>()?;
1125
1126                match ident.resolve(resolve_context!(idx.q))? {
1127                    "doc" => {
1128                        p.expect(K![=])?;
1129
1130                        let str = p.ast::<ast::LitStr>()?;
1131                        let str = str.resolve(resolve_context!(idx.q))?;
1132
1133                        let loc = DynLocation::new(idx.source_id, &*p);
1134
1135                        let item = idx.q.pool.item(idx.item.id);
1136                        let hash = idx.q.pool.item_type_hash(idx.item.id);
1137
1138                        idx.q
1139                            .visitor
1140                            .visit_doc_comment(&loc, item, hash, &str)
1141                            .with_span(&*p)?;
1142                    }
1143                    name => {
1144                        idx.error(Error::msg(
1145                            ident,
1146                            try_format!("unsupported attribute `{name}`"),
1147                        ))?;
1148                    }
1149                }
1150
1151                Ok(())
1152            })?;
1153
1154            p.expect(K![']'])?;
1155            Ok(())
1156        })?;
1157    }
1158
1159    Ok(())
1160}
1161
1162fn fields(idx: &mut Indexer<'_, '_>, p: &mut Stream<'_>) -> Result<meta::Fields> {
1163    match p.kind() {
1164        StructBody => {
1165            p.one(K!['{']).exactly_one(idx)?;
1166            let mut fields = Vec::new();
1167            let mut comma = Remaining::default();
1168
1169            while let MaybeNode::Some(field) = p.eat(Field) {
1170                comma.exactly_one(idx)?;
1171                let name = field.parse(|p| p.ast::<ast::Ident>())?;
1172                let name = name.resolve(resolve_context!(idx.q))?;
1173                let position = fields.len();
1174                fields.try_push(meta::FieldMeta {
1175                    name: name.try_into()?,
1176                    position,
1177                })?;
1178                comma = p.remaining(idx, K![,])?;
1179            }
1180
1181            comma.at_most_one(idx)?;
1182            p.one(K!['}']).exactly_one(idx)?;
1183            Ok(meta::Fields::Named(meta::FieldsNamed {
1184                fields: fields.try_into()?,
1185            }))
1186        }
1187        TupleBody => {
1188            p.one(K!['(']).exactly_one(idx)?;
1189            let mut count = 0;
1190            let mut comma = Remaining::default();
1191
1192            while p.eat(Field).is_some() {
1193                comma.exactly_one(idx)?;
1194                count += 1;
1195                comma = p.remaining(idx, K![,])?;
1196            }
1197
1198            comma.at_most_one(idx)?;
1199            p.one(K![')']).exactly_one(idx)?;
1200            Ok(meta::Fields::Unnamed(count))
1201        }
1202        EmptyBody => Ok(meta::Fields::Empty),
1203        _ => {
1204            idx.error(p.expected("struct body"))?;
1205            Ok(meta::Fields::Empty)
1206        }
1207    }
1208}
1209
1210#[derive(Default, Debug)]
1211struct Mods {
1212    span: Span,
1213    visibility: Visibility,
1214    const_token: Option<ast::Const>,
1215    async_token: Option<ast::Async>,
1216    move_token: Option<ast::Move>,
1217}
1218
1219impl Mods {
1220    /// Parse modifiers.
1221    fn parse(cx: &mut dyn Ignore<'_>, p: &mut Stream<'_>) -> Result<Mods> {
1222        let mut mods = Mods {
1223            span: p.span().head(),
1224            visibility: Visibility::Inherited,
1225            const_token: None,
1226            async_token: None,
1227            move_token: None,
1228        };
1229
1230        loop {
1231            match p.peek() {
1232                K![pub] => {
1233                    mods.visibility = Visibility::Public;
1234                }
1235                ModifierSelf if mods.visibility == Visibility::Public => {
1236                    mods.visibility = Visibility::SelfValue;
1237                }
1238                ModifierSuper if mods.visibility == Visibility::Public => {
1239                    mods.visibility = Visibility::Super;
1240                }
1241                ModifierCrate if mods.visibility == Visibility::Public => {
1242                    mods.visibility = Visibility::Crate;
1243                }
1244                _ => {
1245                    break;
1246                }
1247            }
1248
1249            mods.span = mods.span.join(p.pump()?.span());
1250        }
1251
1252        while let Some(tok) = p.try_ast::<ast::Const>()? {
1253            if mods.const_token.is_some() {
1254                cx.error(Error::msg(tok, "duplicate `const` modifier"))?;
1255            } else {
1256                mods.const_token = Some(tok);
1257            }
1258        }
1259
1260        while let Some(tok) = p.try_ast::<ast::Async>()? {
1261            if mods.async_token.is_some() {
1262                cx.error(Error::msg(tok, "duplicate `async` modifier"))?;
1263            } else {
1264                mods.async_token = Some(tok);
1265            }
1266        }
1267
1268        while let Some(tok) = p.try_ast::<ast::Move>()? {
1269            if mods.move_token.is_some() {
1270                cx.error(Error::msg(tok, "duplicate `move` modifier"))?;
1271            } else {
1272                mods.move_token = Some(tok);
1273            }
1274        }
1275
1276        Ok(mods)
1277    }
1278
1279    /// Deny any existing modifiers.
1280    fn deny_all(self, cx: &mut dyn Ignore<'_>) -> Result<()> {
1281        if !matches!(self.visibility, Visibility::Inherited) {
1282            cx.error(Error::msg(self.span, "unsupported visibility modifier"))?;
1283        }
1284
1285        if let Some(span) = self.const_token {
1286            cx.error(Error::msg(span, "unsupported `const` modifier"))?;
1287        }
1288
1289        if let Some(span) = self.async_token {
1290            cx.error(Error::msg(span, "unsupported `async` modifier"))?;
1291        }
1292
1293        Ok(())
1294    }
1295}