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
mod error;
mod slice;

use std::fmt::Debug;

use crate::input::{self, CompletionRequirement, Input, InputSection, InputToken, UnexpectedToken};

pub use self::error::*;
pub use self::slice::*;

pub trait Context<'i>: Sized + Debug + 'i {
    type Input: Input<'i>;

    fn input(&self) -> Self::Input;
}

type ContextInput<'i, C> = <C as Context<'i>>::Input;
type ContextToken<'i, C> = InputToken<'i, ContextInput<'i, C>>;

pub trait Pass<'i>: Sized + Debug + 'i {
    type Context: Context<'i>;

    type Error: Error<'i, Context = Self::Context>;

    fn context(&self) -> &Self::Context;

    fn into_context(self) -> Self::Context;

    /// Commit the remaining input to be used, consuming the changes.
    fn commit(self, rest: PassInput<'i, Self>) -> Self;

    /// Get the input for this pass.
    fn input<'ii>(&'ii self) -> PassInput<'i, Self> {
        self.context().input()
    }

    /// With input result, mapping the error for a pass.
    fn with<O>(
        input_result: Result<O, PassInputError<'i, Self>>,
        pass: Self,
    ) -> PassResult<'i, Self, O> {
        match input_result {
            Ok(out) => Ok((out, pass)),
            Err(err) => Err(pass.input_error(err)),
        }
    }

    /// Create a pass error based on an input error.
    fn input_error(self, err: PassInputError<'i, Self>) -> Self::Error {
        <PassError<'i, Self> as Error<'i>>::from_input(self.into_context(), err)
    }

    /// Create a pass error based on an incomplete input error.
    fn input_error_incomplete(self, requirement: CompletionRequirement) -> Self::Error {
        self.input_error(<PassInputError<'i, Self> as input::Error<'i>>::incomplete(
            requirement,
        ))
    }

    /// Create a pass error based on an unexpected input error.
    fn input_error_unexpected(
        self,
        unexpected: UnexpectedToken<'i, PassToken<'i, Self>>,
    ) -> Self::Error {
        self.input_error(<PassInputError<'i, Self> as input::Error<'i>>::unexpected(
            unexpected,
        ))
    }

    /// Returns whether or not the input is empty.
    #[inline]
    fn input_is_empty(&'i self) -> bool {
        self.input().is_empty()
    }

    /// Splits the first token from the input.
    #[inline]
    fn split_first(self) -> PassResult<'i, Self, (PassToken<'i, Self>, PassInput<'i, Self>)> {
        <Self as Pass<'i>>::with(self.input().split_first(), self)
    }

    /// Splits an input in two, based on a predictate.
    /// Will fail if cannot split into a pair.
    #[inline]
    fn split_pair<E, F>(
        self,
        pred: F,
    ) -> PassResult<'i, Self, (PassSection<'i, Self>, PassInput<'i, Self>)>
    where
        F: FnMut(&PassToken<'i, Self>) -> bool,
    {
        <Self as Pass<'i>>::with(self.input().split_pair(pred), self)
    }

    /// Splits an input in two, from an exact size.
    #[inline]
    fn split_at<E>(
        self,
        mid: usize,
    ) -> PassResult<'i, Self, (PassSection<'i, Self>, PassInput<'i, Self>)> {
        <Self as Pass<'i>>::with(self.input().split_at(mid), self)
    }
}

pub type PassError<'p, P> = <P as Pass<'p>>::Error;
pub type PassContext<'p, P> = <P as Pass<'p>>::Context;
pub type PassInput<'p, P> = <PassContext<'p, P> as Context<'p>>::Input;
pub type PassToken<'p, P> = InputToken<'p, PassInput<'p, P>>;
pub type PassSection<'p, P> = InputSection<'p, PassInput<'p, P>>;
pub type PassResult<'p, P, O> = Result<(O, P), PassError<'p, P>>;
pub type PassInputError<'i, P> = <<P as Pass<'i>>::Error as Error<'i>>::InputError;

// pub trait PassWithToken<'p, T>: Pass<'p>
// where
//     T: Token,
//     PassInput<'p, Self>: Input<Token = T>,
// {
// }

// impl<'p, P, T> PassWithToken<'p, T> for P
// where
//     T: Token,
//     P: Pass<'p>,
//     PassInput<'p, P>: Input<Token = T>,
// {
// }