bluejay_parser/ast/
directive.rs

1use crate::ast::{Arguments, DepthLimiter, FromTokens, IsMatch, ParseError, Tokens, TryFromTokens};
2use crate::lexical_token::{Name, PunctuatorType};
3use crate::{HasSpan, Span};
4
5#[derive(Debug)]
6pub struct Directive<'a, const CONST: bool> {
7    name: Name<'a>,
8    arguments: Option<Arguments<'a, CONST>>,
9    span: Span,
10}
11
12pub type ConstDirective<'a> = Directive<'a, true>;
13pub type VariableDirective<'a> = Directive<'a, false>;
14
15impl<'a, const CONST: bool> IsMatch<'a> for Directive<'a, CONST> {
16    #[inline]
17    fn is_match(tokens: &mut impl Tokens<'a>) -> bool {
18        tokens.peek_punctuator_matches(0, PunctuatorType::At)
19    }
20}
21
22impl<'a, const CONST: bool> FromTokens<'a> for Directive<'a, CONST> {
23    #[inline]
24    fn from_tokens(
25        tokens: &mut impl Tokens<'a>,
26        depth_limiter: DepthLimiter,
27    ) -> Result<Self, ParseError> {
28        let at_span = tokens.expect_punctuator(PunctuatorType::At)?;
29        let name = tokens.expect_name()?;
30        let arguments = Arguments::try_from_tokens(tokens, depth_limiter.bump()?).transpose()?;
31        let span = match &arguments {
32            Some(arguments) => at_span.merge(arguments.span()),
33            None => at_span.merge(name.span()),
34        };
35
36        Ok(Self {
37            name,
38            arguments,
39            span,
40        })
41    }
42}
43
44impl<'a, const CONST: bool> bluejay_core::Directive<CONST> for Directive<'a, CONST> {
45    type Arguments = Arguments<'a, CONST>;
46
47    fn name(&self) -> &str {
48        self.name.as_ref()
49    }
50
51    fn arguments(&self) -> Option<&Self::Arguments> {
52        self.arguments.as_ref()
53    }
54}
55
56impl<const CONST: bool> HasSpan for Directive<'_, CONST> {
57    fn span(&self) -> &Span {
58        &self.span
59    }
60}
61
62impl<'a, const CONST: bool> Directive<'a, CONST> {
63    pub fn name(&self) -> &Name<'a> {
64        &self.name
65    }
66}