typeql 3.11.0-rc0

TypeQL Language for Rust
Documentation
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

use std::fmt::{self, Write};

use self::isa::Isa;
use super::{Statement, comparison};
use crate::{
    TypeRef,
    common::{Span, Spanned, token},
    expression::Expression,
    pretty::{Pretty, indent},
    type_::TypeRefAny,
    util::write_joined,
    variable::Variable,
};

pub mod isa;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Thing {
    pub span: Option<Span>,
    pub head: Head,
    pub constraints: Vec<Constraint>,
}

impl Thing {
    pub fn new(span: Option<Span>, head: Head, constraints: Vec<Constraint>) -> Self {
        Self { span, head, constraints }
    }
}

impl From<Thing> for Statement {
    fn from(val: Thing) -> Self {
        Statement::Thing(val)
    }
}

impl Spanned for Thing {
    fn span(&self) -> Option<Span> {
        self.span
    }
}

impl Pretty for Thing {
    fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.head)?;
        if let Some((first, rest)) = self.constraints.split_first() {
            f.write_char(' ')?;
            Pretty::fmt(first, indent_level, f)?;
            for constraint in rest {
                f.write_str(",\n")?;
                indent(indent_level + 1, f)?;
                Pretty::fmt(constraint, indent_level + 1, f)?;
            }
        }
        Ok(())
    }
}

impl fmt::Display for Thing {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.head)?;
        if let Some((first, rest)) = self.constraints.split_first() {
            write!(f, " {}", first)?;
            for constraint in rest {
                write!(f, ", {}", constraint)?;
            }
        }
        Ok(())
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Head {
    Variable(Variable),
    Relation(Option<TypeRef>, Relation),
}

impl Pretty for Head {
    fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Variable(inner) => Pretty::fmt(inner, indent_level, f),
            Self::Relation(Some(type_ref), relation) => write!(f, "{} {}", type_ref, relation),
            Self::Relation(None, relation) => Pretty::fmt(relation, indent_level, f),
        }
    }
}

impl fmt::Display for Head {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Variable(inner) => fmt::Display::fmt(inner, f),
            Self::Relation(Some(type_ref), relation) => write!(f, "{} {}", type_ref, relation),
            Self::Relation(None, inner) => fmt::Display::fmt(inner, f),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Relation {
    pub span: Option<Span>,
    pub role_players: Vec<RolePlayer>,
}

impl Relation {
    pub(crate) fn new(span: Option<Span>, role_players: Vec<RolePlayer>) -> Self {
        Self { span, role_players }
    }
}

impl Spanned for Relation {
    fn span(&self) -> Option<Span> {
        self.span
    }
}

impl Pretty for Relation {}

impl fmt::Display for Relation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_char('(')?;
        write_joined!(f, ", ", self.role_players)?;
        f.write_char(')')?;
        Ok(())
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum RolePlayer {
    Typed(TypeRefAny, Variable),
    Untyped(Variable),
}

impl Pretty for RolePlayer {}

impl fmt::Display for RolePlayer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            RolePlayer::Typed(type_, var) => write!(f, "{type_}: {var}"),
            RolePlayer::Untyped(var) => write!(f, "{var}"),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Constraint {
    Isa(Isa),
    Iid(Iid),
    Has(Has),
    Links(Links),
}

impl Pretty for Constraint {
    fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Isa(inner) => Pretty::fmt(inner, indent_level, f),
            Self::Iid(inner) => Pretty::fmt(inner, indent_level, f),
            Self::Has(inner) => Pretty::fmt(inner, indent_level, f),
            Self::Links(inner) => Pretty::fmt(inner, indent_level, f),
        }
    }
}

impl fmt::Display for Constraint {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Isa(inner) => fmt::Display::fmt(inner, f),
            Self::Iid(inner) => fmt::Display::fmt(inner, f),
            Self::Has(inner) => fmt::Display::fmt(inner, f),
            Self::Links(inner) => fmt::Display::fmt(inner, f),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Iid {
    pub span: Option<Span>,
    pub iid: String,
}

impl Iid {
    pub(crate) fn new(span: Option<Span>, iid: String) -> Self {
        Self { span, iid }
    }
}

impl Spanned for Iid {
    fn span(&self) -> Option<Span> {
        self.span
    }
}

impl Pretty for Iid {}

impl fmt::Display for Iid {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} {}", token::Keyword::IID, self.iid)
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Has {
    pub span: Option<Span>,
    pub type_: Option<TypeRefAny>,
    pub value: HasValue,
}

impl Has {
    pub fn new(span: Option<Span>, type_: Option<TypeRefAny>, value: HasValue) -> Self {
        Self { span, type_, value }
    }
}

impl Spanned for Has {
    fn span(&self) -> Option<Span> {
        self.span
    }
}

impl Pretty for Has {}

impl fmt::Display for Has {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", token::Keyword::Has)?;
        if let Some(type_) = &self.type_ {
            write!(f, " {}", type_)?;
        }
        write!(f, " {}", self.value)?;
        Ok(())
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum HasValue {
    Variable(Variable),
    Expression(Expression),
    Comparison(comparison::Comparison),
}

impl Pretty for HasValue {
    fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Variable(inner) => Pretty::fmt(inner, indent_level, f),
            Self::Expression(inner) => Pretty::fmt(inner, indent_level, f),
            Self::Comparison(inner) => Pretty::fmt(inner, indent_level, f),
        }
    }
}

impl fmt::Display for HasValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Variable(inner) => fmt::Display::fmt(inner, f),
            Self::Expression(inner) => fmt::Display::fmt(inner, f),
            Self::Comparison(inner) => fmt::Display::fmt(inner, f),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Links {
    pub span: Option<Span>,
    pub relation: Relation,
}

impl Links {
    pub fn new(span: Option<Span>, relation: Relation) -> Self {
        Self { span, relation }
    }
}

impl Spanned for Links {
    fn span(&self) -> Option<Span> {
        self.span
    }
}

impl Pretty for Links {}

impl fmt::Display for Links {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} {}", token::Keyword::Links, self.relation)
    }
}