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
use crate::{
    parser::{statements, streaming_statements},
    Block, Error, NomResult, Span, Spanned,
};

use core::fmt;

/// Parsing features for a `Grammar`.
// TODO: make boolean expressions optional, too.
#[derive(Debug, Clone)]
pub struct Features {
    /// Parse tuple types?
    pub tuples: bool,
    /// Parse type annotations?
    pub type_annotations: bool,
    /// Parse function definitions?
    pub fn_definitions: bool,
    /// Parse blocks?
    pub blocks: bool,
    /// Parse methods?
    pub methods: bool,
}

impl Features {
    /// Returns the set of all available features.
    pub const fn all() -> Self {
        Self {
            tuples: true,
            type_annotations: true,
            fn_definitions: true,
            blocks: true,
            methods: true,
        }
    }

    /// Returns the set with all features disabled.
    pub const fn none() -> Self {
        Self {
            tuples: false,
            type_annotations: false,
            fn_definitions: false,
            blocks: false,
            methods: false,
        }
    }
}

impl Default for Features {
    fn default() -> Self {
        Self::all()
    }
}

/// Unites all necessary parsers to form a complete grammar definition.
pub trait Grammar: 'static {
    /// Type of the literal used in the grammar.
    type Lit: Clone + fmt::Debug;
    /// Type of the type declaration used in the grammar.
    type Type: Clone + fmt::Debug;

    /// Features supported by this grammar.
    const FEATURES: Features;

    /// Attempts to parse a literal.
    ///
    /// # Return value
    ///
    /// The output should follow `nom` conventions on errors / failures.
    fn parse_literal(input: Span<'_>) -> NomResult<'_, Self::Lit>;

    /// Attempts to parse a type hint.
    ///
    /// # Return value
    ///
    /// The output should follow `nom` conventions on errors / failures.
    fn parse_type(input: Span<'_>) -> NomResult<'_, Self::Type>;
}

/// Extension trait for `Grammar` used by the client applications.
pub trait GrammarExt: Grammar {
    /// Parses a list of statements.
    fn parse_statements(input: Span<'_>) -> Result<Block<'_, Self>, Spanned<'_, Error<'_>>>
    where
        Self: Sized;

    /// Parses a potentially incomplete list of statements.
    fn parse_streaming_statements(
        input: Span<'_>,
    ) -> Result<Block<'_, Self>, Spanned<'_, Error<'_>>>
    where
        Self: Sized;
}

impl<T: Grammar> GrammarExt for T {
    fn parse_statements(input: Span<'_>) -> Result<Block<'_, Self>, Spanned<'_, Error<'_>>>
    where
        Self: Sized,
    {
        statements(input)
    }

    fn parse_streaming_statements(
        input: Span<'_>,
    ) -> Result<Block<'_, Self>, Spanned<'_, Error<'_>>>
    where
        Self: Sized,
    {
        streaming_statements(input)
    }
}