rune/query/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
//! Lazy query system, used to compile and build items on demand and keep track
//! of what's being used and not.

mod query;

use core::fmt;
use core::mem::take;
use core::num::NonZeroUsize;

use rust_alloc::rc::Rc;

pub(crate) use self::query::{Query, QueryInner, QuerySource};

use crate as rune;
use crate::alloc::path::PathBuf;
use crate::alloc::prelude::*;
use crate::ast::{self, OptionSpanned, Span, Spanned};
use crate::compile::{ir, Doc, Error, ItemId, ItemMeta, Location, ModId, Result};
use crate::grammar::{Ignore, Node, NodeAt, NodeId, Tree};
use crate::hash::Hash;
use crate::hir;
use crate::indexing;
use crate::parse::NonZeroId;
use crate::runtime::format;
use crate::runtime::Call;

/// Indication whether a value is being evaluated because it's being used or not.
#[derive(Default, Debug, TryClone, Clone, Copy)]
#[try_clone(copy)]
pub(crate) enum Used {
    /// The value is not being used.
    Unused,
    /// The value is being used.
    #[default]
    Used,
}

impl Used {
    /// Test if this used indicates unuse.
    pub(crate) fn is_unused(self) -> bool {
        matches!(self, Self::Unused)
    }
}

/// The result of calling [Query::convert_path].
pub(crate) struct Named<'ast> {
    /// Module named item belongs to.
    pub(crate) module: ModId,
    /// The path resolved to the given item.
    pub(crate) item: ItemId,
    /// Trailing parameters.
    pub(crate) trailing: usize,
    /// Type parameters if any.
    pub(crate) parameters: [Option<(
        &'ast dyn Spanned,
        &'ast ast::AngleBracketed<ast::PathSegmentExpr, T![,]>,
    )>; 2],
}

impl fmt::Display for Named<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.item, f)
    }
}

pub(crate) enum Named2Kind {
    /// A full path.
    Full,
    /// An identifier.
    Ident(ast::Ident),
    /// Self value.
    SelfValue(#[allow(unused)] ast::SelfValue),
}

/// The result of calling [Query::convert_path2].
pub(crate) struct Named2<'a> {
    /// Module named item belongs to.
    pub(crate) module: ModId,
    /// The kind of named item.
    pub(crate) kind: Named2Kind,
    /// The path resolved to the given item.
    pub(crate) item: ItemId,
    /// Trailing parameters.
    pub(crate) trailing: usize,
    /// Type parameters if any.
    pub(crate) parameters: [Option<Node<'a>>; 2],
}

impl fmt::Display for Named2<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.item, f)
    }
}

/// An internally resolved macro.
#[allow(clippy::large_enum_variant)]
pub(crate) enum BuiltInMacro {
    Template(BuiltInTemplate),
    Format(BuiltInFormat),
    File(BuiltInFile),
    Line(BuiltInLine),
}

pub(crate) enum BuiltInMacro2 {
    File(ast::LitStr),
    Line(usize),
    Template(Rc<Tree>, BuiltInLiteral),
    Format(Rc<Tree>),
}

/// An internally resolved template.
#[derive(Spanned)]
pub(crate) struct BuiltInTemplate {
    /// The span of the built-in template.
    #[rune(span)]
    pub(crate) span: Span,
    /// Indicate if template originated from literal.
    pub(crate) from_literal: bool,
    /// Expressions being concatenated as a template.
    pub(crate) exprs: Vec<ast::Expr>,
}

/// An internal format specification.
#[derive(Spanned)]
pub(crate) struct BuiltInFormat {
    #[rune(span)]
    pub(crate) span: Span,
    /// The fill character to use.
    pub(crate) fill: Option<char>,
    /// Alignment specification.
    pub(crate) align: Option<format::Alignment>,
    /// Width to fill.
    pub(crate) width: Option<NonZeroUsize>,
    /// Precision to fill.
    pub(crate) precision: Option<NonZeroUsize>,
    /// A specification of flags.
    pub(crate) flags: Option<format::Flags>,
    /// The format specification type.
    pub(crate) format_type: Option<format::Type>,
    /// The value being formatted.
    pub(crate) value: ast::Expr,
}

/// Macro data for `file!()`
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)]
#[try_clone(copy)]
pub(crate) struct BuiltInFile {
    /// Path value to use
    pub(crate) value: ast::Lit,
}

/// Macro data for `line!()`
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)]
#[try_clone(copy)]
pub(crate) struct BuiltInLine {
    /// The line number
    pub(crate) value: ast::Lit,
}

#[derive(Debug, TryClone)]
pub(crate) struct Closure<'hir> {
    /// Ast for closure.
    pub(crate) hir: &'hir hir::ExprClosure<'hir>,
    /// Calling convention used for closure.
    pub(crate) call: Call,
}

#[derive(Debug, TryClone)]
pub(crate) struct AsyncBlock<'hir> {
    /// Ast for block.
    pub(crate) hir: &'hir hir::AsyncBlock<'hir>,
    /// Calling convention used for async block.
    pub(crate) call: Call,
}

/// An entry in the build queue.
#[derive(Debug, TryClone)]
pub(crate) enum SecondaryBuild<'hir> {
    Closure(Closure<'hir>),
    AsyncBlock(AsyncBlock<'hir>),
}

/// An entry in the build queue.
#[derive(Debug, TryClone)]
pub(crate) struct SecondaryBuildEntry<'hir> {
    /// The item of the build entry.
    pub(crate) item_meta: ItemMeta,
    /// The build entry.
    pub(crate) build: SecondaryBuild<'hir>,
}

/// An entry in the build queue.
#[derive(Debug, TryClone)]
pub(crate) enum Build {
    Function(indexing::Function),
    Unused,
    Import(indexing::Import),
    /// A public re-export.
    ReExport,
    /// A build which simply queries for the item.
    Query,
}

/// An entry in the build queue.
#[derive(Debug, TryClone)]
pub(crate) struct BuildEntry {
    /// The item of the build entry.
    pub(crate) item_meta: ItemMeta,
    /// The build entry.
    pub(crate) build: Build,
}

/// The kind of item being implemented.
pub(crate) enum ImplItemKind {
    Ast {
        /// Non-expanded ast of the path.
        path: Box<ast::Path>,
        /// Functions in the impl block.
        functions: Vec<ast::ItemFn>,
    },
    Node {
        /// The path being implemented.
        path: NodeAt,
        /// Functions being added.
        functions: Vec<(NodeId, Attrs)>,
    },
}

#[must_use = "must be consumed"]
#[derive(Default, Debug)]
pub(crate) struct Attrs {
    pub(crate) test: Option<Span>,
    pub(crate) bench: Option<Span>,
    pub(crate) docs: Vec<Doc>,
    pub(crate) builtin: Option<(Span, BuiltInLiteral)>,
}

impl Attrs {
    pub(crate) fn deny_non_docs(self, cx: &mut dyn Ignore<'_>) -> Result<()> {
        if let Some(span) = self.test {
            cx.error(Error::msg(span, "unsupported #[test] attribute"))?;
        }

        if let Some(span) = self.bench {
            cx.error(Error::msg(span, "unsupported #[bench] attribute"))?;
        }

        if let Some((span, _)) = self.builtin {
            cx.error(Error::msg(span, "unsupported #[builtin] attribute"))?;
        }

        Ok(())
    }

    pub(crate) fn deny_any(self, cx: &mut dyn Ignore<'_>) -> Result<()> {
        if let Some(span) = self.docs.option_span() {
            cx.error(Error::msg(span, "unsupported documentation"))?;
        }

        self.deny_non_docs(cx)?;
        Ok(())
    }
}

/// The implementation item.
pub(crate) struct ImplItem {
    /// The kind of item being implemented.
    pub(crate) kind: ImplItemKind,
    /// Location where the item impl is defined and is being expanded.
    pub(crate) location: Location,
    ///See [Indexer][crate::indexing::Indexer].
    pub(crate) root: Option<PathBuf>,
    ///See [Indexer][crate::indexing::Indexer].
    pub(crate) nested_item: Option<Span>,
    /// See [Indexer][crate::indexing::Indexer].
    pub(crate) macro_depth: usize,
}

/// Expand the given macro.
#[must_use = "Must be used to report errors"]
pub(crate) struct ExpandMacroBuiltin {
    /// The identifier of the macro being expanded.
    pub(crate) id: NonZeroId,
    /// The macro being expanded.
    pub(crate) node: NodeAt,
    /// Location where the item impl is defined and is being expanded.
    pub(crate) location: Location,
    ///See [Indexer][crate::indexing::Indexer].
    pub(crate) root: Option<PathBuf>,
    /// See [Indexer][crate::indexing::Indexer].
    pub(crate) macro_depth: usize,
    /// Indexing item at macro expansion position.
    pub(crate) item: indexing::IndexItem,
    /// The literal option.
    pub(crate) literal: BuiltInLiteral,
}

impl ExpandMacroBuiltin {
    /// Deny any unused options.
    pub(crate) fn finish(self) -> Result<NonZeroId> {
        if let BuiltInLiteral::Yes(span) = self.literal {
            return Err(Error::msg(
                span,
                "#[builtin(literal)] option is not allowed",
            ));
        }

        Ok(self.id)
    }
}

/// Whether the literal option is set.
#[derive(Default, Debug)]
pub(crate) enum BuiltInLiteral {
    Yes(Span),
    #[default]
    No,
}

impl BuiltInLiteral {
    /// Take the literal option.
    pub(crate) fn take(&mut self) -> Self {
        take(self)
    }

    /// Test if the literal option is set.
    pub(crate) fn is_yes(&self) -> bool {
        matches!(self, Self::Yes(_))
    }
}

/// A deferred build entry.
pub(crate) enum DeferEntry {
    ImplItem(ImplItem),
    ExpandMacroBuiltin(ExpandMacroBuiltin),
    ExpandMacroCall(ExpandMacroBuiltin),
}

/// A compiled constant function.
pub(crate) struct ConstFn<'hir> {
    /// The item of the const fn.
    pub(crate) item_meta: ItemMeta,
    /// The soon-to-be deprecated IR function.
    pub(crate) ir_fn: ir::IrFn,
    /// HIR function associated with this constant function.
    #[allow(unused)]
    pub(crate) hir: hir::ItemFn<'hir>,
}

/// The data of a macro call.
pub(crate) enum ExpandedMacro {
    /// A built-in expanded macro.
    Builtin(BuiltInMacro2),
    /// The expanded body of a macro.
    Tree(Rc<Tree>),
}

/// Generic parameters.
#[derive(Default)]
pub(crate) struct GenericsParameters {
    pub(crate) trailing: usize,
    pub(crate) parameters: [Option<Hash>; 2],
}

impl GenericsParameters {
    pub(crate) fn is_empty(&self) -> bool {
        self.parameters.iter().all(|p| p.is_none())
    }
}

impl fmt::Debug for GenericsParameters {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut f = f.debug_list();

        for p in &self.parameters[2 - self.trailing..] {
            f.entry(p);
        }

        f.finish()
    }
}

impl AsRef<GenericsParameters> for GenericsParameters {
    #[inline]
    fn as_ref(&self) -> &GenericsParameters {
        self
    }
}