#![doc(html_root_url = "https://docs.rs/dhall/0.2.1")]
#![feature(never_type)]
#![allow(
clippy::type_complexity,
clippy::infallible_destructuring_match,
clippy::many_single_char_names,
clippy::match_wild_err_arm,
clippy::redundant_closure,
clippy::ptr_arg
)]
mod tests;
pub mod error;
pub mod semantics;
pub mod syntax;
use std::fmt::Display;
use std::path::Path;
use crate::error::{EncodeError, Error, TypeError};
use crate::semantics::parse;
use crate::semantics::resolve;
use crate::semantics::resolve::ImportRoot;
use crate::semantics::{
typecheck, typecheck_with, Hir, TyExpr, Value, ValueKind,
};
use crate::syntax::binary;
use crate::syntax::{Builtin, Expr};
pub type ParsedExpr = Expr;
pub type DecodedExpr = Expr;
pub type ResolvedExpr = Expr;
pub type NormalizedExpr = Expr;
#[derive(Debug, Clone)]
pub struct Parsed(ParsedExpr, ImportRoot);
/// An expression where all imports have been resolved
///
/// Invariant: there must be no `Import` nodes or `ImportAlt` operations left.
#[derive(Debug, Clone)]
pub struct Resolved(Hir);
/// A typed expression
#[derive(Debug, Clone)]
pub struct Typed(TyExpr);
/// A normalized expression.
///
/// Invariant: the contained Typed expression must be in normal form,
#[derive(Debug, Clone)]
pub struct Normalized(Value);
/// Controls conversion from `Value` to `Expr`
#[derive(Copy, Clone)]
pub(crate) struct ToExprOptions {
/// Whether to convert all variables to `_`
pub(crate) alpha: bool,
/// Whether to normalize before converting
pub(crate) normalize: bool,
}
impl Parsed {
pub fn parse_file(f: &Path) -> Result {
parse::parse_file(f)
}
pub fn parse_str(s: &str) -> Result {
parse::parse_str(s)
}
pub fn parse_binary_file(f: &Path) -> Result {
parse::parse_binary_file(f)
}
pub fn parse_binary(data: &[u8]) -> Result {
parse::parse_binary(data)
}
pub fn resolve(self) -> Result {
resolve::resolve(self)
}
pub fn skip_resolve(self) -> Result {
Ok(Resolved(resolve::skip_resolve(&self.0)?))
}
pub fn encode(&self) -> Result, EncodeError> {
binary::encode(&self.0)
}
/// Converts a value back to the corresponding AST expression.
pub fn to_expr(&self) -> ParsedExpr {
self.0.clone()
}
}
impl Resolved {
pub fn typecheck(&self) -> Result {
Ok(Typed(typecheck(&self.0)?))
}
pub fn typecheck_with(self, ty: &Normalized) -> Result {
Ok(Typed(typecheck_with(&self.0, ty.to_hir())?))
}
/// Converts a value back to the corresponding AST expression.
pub fn to_expr(&self) -> ResolvedExpr {
self.0.to_expr_noopts()
}
}
impl Typed {
/// Reduce an expression to its normal form, performing beta reduction
pub fn normalize(&self) -> Normalized {
Normalized(self.0.rec_eval_closed_expr())
}
/// Converts a value back to the corresponding AST expression.
fn to_expr(&self) -> ResolvedExpr {
self.0.to_expr(ToExprOptions {
alpha: false,
normalize: false,
})
}
pub(crate) fn get_type(&self) -> Result {
Ok(Normalized(self.0.ty().clone()))
}
}
impl Normalized {
pub fn encode(&self) -> Result, EncodeError> {
binary::encode(&self.to_expr())
}
/// Converts a value back to the corresponding AST expression.
pub fn to_expr(&self) -> NormalizedExpr {
self.0.to_expr(ToExprOptions {
alpha: false,
normalize: false,
})
}
/// Converts a value back to the corresponding Hir expression.
pub(crate) fn to_hir(&self) -> Hir {
self.0.to_hir_noenv()
}
/// Converts a value back to the corresponding AST expression, alpha-normalizing in the process.
pub(crate) fn to_expr_alpha(&self) -> NormalizedExpr {
self.0.to_expr(ToExprOptions {
alpha: true,
normalize: false,
})
}
pub(crate) fn to_value(&self) -> Value {
self.0.clone()
}
pub(crate) fn into_value(self) -> Value {
self.0
}
pub(crate) fn from_kind(v: ValueKind) -> Self {
Normalized(Value::from_kind(v))
}
pub(crate) fn from_value(th: Value) -> Self {
Normalized(th)
}
pub fn make_builtin_type(b: Builtin) -> Self {
Normalized::from_value(Value::from_builtin(b))
}
pub fn make_optional_type(t: Normalized) -> Self {
Normalized::from_value(
Value::from_builtin(Builtin::Optional).app(t.to_value()),
)
}
pub fn make_list_type(t: Normalized) -> Self {
Normalized::from_value(
Value::from_builtin(Builtin::List).app(t.to_value()),
)
}
pub fn make_record_type(
kts: impl Iterator- ,
) -> Self {
Normalized::from_kind(ValueKind::RecordType(
kts.map(|(k, t)| (k.into(), t.into_value())).collect(),
))
}
pub fn make_union_type(
kts: impl Iterator
- )>,
) -> Self {
Normalized::from_kind(ValueKind::UnionType(
kts.map(|(k, t)| (k.into(), t.map(|t| t.into_value())))
.collect(),
))
}
}
macro_rules! derive_traits_for_wrapper_struct {
($ty:ident) => {
impl std::cmp::PartialEq for $ty {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl std::cmp::Eq for $ty {}
impl std::fmt::Display for $ty {
fn fmt(
&self,
f: &mut std::fmt::Formatter,
) -> Result<(), std::fmt::Error> {
self.0.fmt(f)
}
}
};
}
derive_traits_for_wrapper_struct!(Parsed);
impl std::hash::Hash for Normalized {
fn hash(&self, state: &mut H)
where
H: std::hash::Hasher,
{
if let Ok(vec) = self.encode() {
vec.hash(state)
}
}
}
impl From for NormalizedExpr {
fn from(other: Parsed) -> Self {
other.to_expr()
}
}
impl From for NormalizedExpr {
fn from(other: Normalized) -> Self {
other.to_expr()
}
}
impl Display for Resolved {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
self.to_expr().fmt(f)
}
}
impl Eq for Typed {}
impl PartialEq for Typed {
fn eq(&self, other: &Self) -> bool {
self.normalize() == other.normalize()
}
}
impl Display for Typed {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
self.to_expr().fmt(f)
}
}
impl Eq for Normalized {}
impl PartialEq for Normalized {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Display for Normalized {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
self.to_expr().fmt(f)
}
}