bluejay-parser 0.3.1

A GraphQL parser
Documentation
use crate::ast::{DepthLimiter, FromTokens, ParseError, Tokens};
use crate::lexical_token::{
    FloatValue, IntValue, LexicalToken, Name, PunctuatorType, StringValue, Variable,
};
use crate::{HasSpan, Span};
use bluejay_core::{
    AsIter, ListValue as CoreListValue, ObjectValue as CoreObjectValue, Value as CoreValue,
    ValueReference,
};

#[derive(Debug)]
pub enum Value<'a, const CONST: bool> {
    Variable(Variable<'a>),
    Integer(IntValue),
    Float(FloatValue),
    String(StringValue<'a>),
    Boolean(BooleanValue),
    Null(Name<'a>),
    Enum(Name<'a>),
    List(ListValue<'a, CONST>),
    Object(ObjectValue<'a, CONST>),
}

impl<'a, const CONST: bool> CoreValue<CONST> for Value<'a, CONST> {
    type List = ListValue<'a, CONST>;
    type Object = ObjectValue<'a, CONST>;
    type Variable = Variable<'a>;

    fn as_ref(&self) -> ValueReference<'_, CONST, Self> {
        match self {
            Self::Variable(v) => ValueReference::Variable(v),
            Self::Integer(i) => ValueReference::Integer(i.value()),
            Self::Float(f) => ValueReference::Float(f.value()),
            Self::String(s) => ValueReference::String(s.as_ref()),
            Self::Boolean(b) => ValueReference::Boolean(b.value()),
            Self::Null(_) => ValueReference::Null,
            Self::Enum(e) => ValueReference::Enum(e.as_ref()),
            Self::List(l) => ValueReference::List(l),
            Self::Object(o) => ValueReference::Object(o),
        }
    }
}

impl<'a, const CONST: bool> FromTokens<'a> for Value<'a, CONST> {
    fn from_tokens(
        tokens: &mut impl Tokens<'a>,
        depth_limiter: DepthLimiter,
    ) -> Result<Self, ParseError> {
        match tokens.next() {
            Some(LexicalToken::IntValue(int)) => Ok(Self::Integer(int)),
            Some(LexicalToken::FloatValue(float)) => Ok(Self::Float(float)),
            Some(LexicalToken::StringValue(string)) => Ok(Self::String(string)),
            Some(LexicalToken::Name(name)) => Ok(match name.as_str() {
                "true" => Self::Boolean(BooleanValue {
                    value: true,
                    span: name.into(),
                }),
                "false" => Self::Boolean(BooleanValue {
                    value: false,
                    span: name.into(),
                }),
                "null" => Self::Null(name),
                _ => Self::Enum(name),
            }),
            Some(LexicalToken::VariableName(name)) => {
                if CONST {
                    Err(ParseError::UnexpectedToken { span: name.into() })
                } else {
                    Ok(Self::Variable(name))
                }
            }
            Some(LexicalToken::Punctuator(p))
                if p.r#type() == PunctuatorType::OpenSquareBracket =>
            {
                let open_span = p.span().clone();
                let mut list: Vec<Self> = Vec::new();
                let close_span = loop {
                    if let Some(close_span) =
                        tokens.next_if_punctuator(PunctuatorType::CloseSquareBracket)
                    {
                        break close_span;
                    }
                    list.push(Self::from_tokens(tokens, depth_limiter.bump()?)?);
                };
                let span = open_span.merge(&close_span);
                Ok(Self::List(ListValue {
                    elements: list,
                    span,
                }))
            }
            Some(LexicalToken::Punctuator(p)) if p.r#type() == PunctuatorType::OpenBrace => {
                let open_span = p.span().clone();
                let mut object: Vec<_> = Vec::new();
                let close_span = loop {
                    if let Some(close_span) = tokens.next_if_punctuator(PunctuatorType::CloseBrace)
                    {
                        break close_span;
                    }
                    let name = tokens.expect_name()?;
                    tokens.expect_punctuator(PunctuatorType::Colon)?;
                    let value = Self::from_tokens(tokens, depth_limiter.bump()?)?;
                    object.push((name, value));
                };
                let span = open_span.merge(&close_span);
                Ok(Self::Object(ObjectValue {
                    fields: object,
                    span,
                }))
            }
            token => Err(token
                .map(|token| ParseError::UnexpectedToken { span: token.into() })
                .unwrap_or_else(|| tokens.unexpected_eof())),
        }
    }
}

impl<const CONST: bool> HasSpan for Value<'_, CONST> {
    fn span(&self) -> &Span {
        match self {
            Self::Boolean(b) => &b.span,
            Self::Enum(e) => e.span(),
            Self::Float(f) => f.span(),
            Self::Integer(i) => i.span(),
            Self::List(l) => &l.span,
            Self::Null(n) => n.span(),
            Self::Object(o) => &o.span,
            Self::String(s) => s.span(),
            Self::Variable(v) => v.span(),
        }
    }
}

pub type ConstValue<'a> = Value<'a, true>;
pub type VariableValue<'a> = Value<'a, false>;

#[derive(Debug)]
pub struct BooleanValue {
    value: bool,
    span: Span,
}

impl BooleanValue {
    fn value(&self) -> bool {
        self.value
    }
}

#[derive(Debug)]
pub struct ListValue<'a, const CONST: bool> {
    elements: Vec<Value<'a, CONST>>,
    span: Span,
}

impl<'a, const CONST: bool> CoreListValue<CONST> for ListValue<'a, CONST> {
    type Value = Value<'a, CONST>;
}

impl<'a, const CONST: bool> AsIter for ListValue<'a, CONST> {
    type Item = Value<'a, CONST>;
    type Iterator<'b>
        = std::slice::Iter<'b, Self::Item>
    where
        'a: 'b;

    fn iter(&self) -> Self::Iterator<'_> {
        self.elements.iter()
    }
}

#[derive(Debug)]
pub struct ObjectValue<'a, const CONST: bool> {
    fields: Vec<(Name<'a>, Value<'a, CONST>)>,
    span: Span,
}

impl<'a, const CONST: bool> CoreObjectValue<CONST> for ObjectValue<'a, CONST> {
    type Key = Name<'a>;
    type Value = Value<'a, CONST>;
    type Iterator<'b>
        = std::iter::Map<
        std::slice::Iter<'b, (Name<'a>, Value<'a, CONST>)>,
        fn(&'b (Name<'a>, Value<'a, CONST>)) -> (&'b Name<'a>, &'b Value<'a, CONST>),
    >
    where
        'a: 'b;

    fn iter(&self) -> Self::Iterator<'_> {
        self.fields.iter().map(|(key, value)| (key, value))
    }
}

impl<'a, const CONST: bool> AsIter for ObjectValue<'a, CONST> {
    type Item = (Name<'a>, Value<'a, CONST>);
    type Iterator<'b>
        = std::slice::Iter<'b, (Name<'a>, Value<'a, CONST>)>
    where
        'a: 'b;

    fn iter(&self) -> Self::Iterator<'_> {
        self.fields.iter()
    }
}

impl<const CONST: bool> HasSpan for ObjectValue<'_, CONST> {
    fn span(&self) -> &Span {
        &self.span
    }
}