From 9741e3280ed03920732430e7994e1f8482c9ddd6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 6 Apr 2019 17:48:13 +0200 Subject: s/DhallError/ImportError/ --- dhall/tests/common/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'dhall/tests') diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs index 397a8ee..e748cf0 100644 --- a/dhall/tests/common/mod.rs +++ b/dhall/tests/common/mod.rs @@ -44,13 +44,13 @@ pub enum Feature { TypeInferenceFailure, } -pub fn read_dhall_file<'i>(file_path: &str) -> Result, DhallError> { +pub fn read_dhall_file<'i>(file_path: &str) -> Result, ImportError> { load_dhall_file(&PathBuf::from(file_path), true) } pub fn read_dhall_file_no_resolve_imports<'i>( file_path: &str, -) -> Result { +) -> Result { load_dhall_file_no_resolve_imports(&PathBuf::from(file_path)) } @@ -93,7 +93,7 @@ pub fn run_test(base_path: &str, feature: Feature) { let err = read_dhall_file_no_resolve_imports(&file_path).unwrap_err(); match err { - DhallError::ParseError(_) => {} + ImportError::ParseError(_) => {} e => panic!("Expected parse error, got: {:?}", e), } } -- cgit v1.3.1 From d9b4bd8d4019ca9ab999c0c4657663604158101c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 6 Apr 2019 17:50:47 +0200 Subject: s/Type/StaticType/ --- dhall/src/dhall_type.rs | 22 +++++++++++----------- dhall/src/lib.rs | 3 +-- dhall/tests/dhall_type.rs | 14 +++++++------- dhall_generator/src/dhall_type.rs | 10 +++++----- dhall_generator/src/lib.rs | 2 +- 5 files changed, 25 insertions(+), 26 deletions(-) (limited to 'dhall/tests') diff --git a/dhall/src/dhall_type.rs b/dhall/src/dhall_type.rs index 6b0e06e..64e07d9 100644 --- a/dhall/src/dhall_type.rs +++ b/dhall/src/dhall_type.rs @@ -4,37 +4,37 @@ use dhall_generator::*; #[derive(Debug, Clone)] pub enum ConversionError {} -pub trait Type { +pub trait StaticType { fn get_type() -> DhallExpr; // fn as_dhall(&self) -> DhallExpr; // fn from_dhall(e: DhallExpr) -> Result; } -impl Type for bool { +impl StaticType for bool { fn get_type() -> DhallExpr { dhall_expr!(Bool) } } -impl Type for Natural { +impl StaticType for Natural { fn get_type() -> DhallExpr { dhall_expr!(Natural) } } -impl Type for Integer { +impl StaticType for Integer { fn get_type() -> DhallExpr { dhall_expr!(Integer) } } -impl Type for String { +impl StaticType for String { fn get_type() -> DhallExpr { dhall_expr!(Text) } } -impl Type for (A, B) { +impl StaticType for (A, B) { fn get_type() -> DhallExpr { let ta = A::get_type(); let tb = B::get_type(); @@ -42,33 +42,33 @@ impl Type for (A, B) { } } -impl Type for Option { +impl StaticType for Option { fn get_type() -> DhallExpr { let t = T::get_type(); dhall_expr!(Optional t) } } -impl Type for Vec { +impl StaticType for Vec { fn get_type() -> DhallExpr { let t = T::get_type(); dhall_expr!(List t) } } -impl<'a, T: Type> Type for &'a T { +impl<'a, T: StaticType> StaticType for &'a T { fn get_type() -> DhallExpr { T::get_type() } } -impl Type for std::marker::PhantomData { +impl StaticType for std::marker::PhantomData { fn get_type() -> DhallExpr { dhall_expr!({}) } } -impl Type for Result { +impl StaticType for Result { fn get_type() -> DhallExpr { let tt = T::get_type(); let te = E::get_type(); diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index 103fd29..5a155c8 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -16,8 +16,7 @@ pub mod typecheck; pub use crate::dhall_type::*; pub use dhall_generator::expr; pub use dhall_generator::subexpr; -pub use dhall_generator::Type; - +pub use dhall_generator::StaticType; pub use crate::imports::*; // pub struct DhallExpr(dhall_core::DhallExpr); diff --git a/dhall/tests/dhall_type.rs b/dhall/tests/dhall_type.rs index 941e3a4..ac6b5e6 100644 --- a/dhall/tests/dhall_type.rs +++ b/dhall/tests/dhall_type.rs @@ -1,5 +1,5 @@ #![feature(proc_macro_hygiene)] -use dhall::Type; +use dhall::StaticType; use dhall_generator::dhall_expr; #[test] @@ -11,18 +11,18 @@ fn test_dhall_type() { dhall_expr!({ _1: Bool, _2: Optional Text }) ); - #[derive(dhall::Type)] + #[derive(dhall::StaticType)] #[allow(dead_code)] struct A { field1: bool, field2: Option, } assert_eq!( - ::get_type(), + ::get_type(), dhall_expr!({ field1: Bool, field2: Optional Bool }) ); - #[derive(Type)] + #[derive(StaticType)] #[allow(dead_code)] struct B<'a, T: 'a> { field1: &'a T, @@ -30,12 +30,12 @@ fn test_dhall_type() { } assert_eq!(>::get_type(), A::get_type()); - #[derive(Type)] + #[derive(StaticType)] #[allow(dead_code)] struct C(T, Option); assert_eq!(>::get_type(), <(bool, Option)>::get_type()); - #[derive(Type)] + #[derive(StaticType)] #[allow(dead_code)] struct D(); assert_eq!( @@ -43,7 +43,7 @@ fn test_dhall_type() { dhall_expr!({ _1: {}, _2: Optional Text }) ); - #[derive(Type)] + #[derive(StaticType)] #[allow(dead_code)] enum E { A(T), diff --git a/dhall_generator/src/dhall_type.rs b/dhall_generator/src/dhall_type.rs index 3b1d1c9..38c871d 100644 --- a/dhall_generator/src/dhall_type.rs +++ b/dhall_generator/src/dhall_type.rs @@ -44,7 +44,7 @@ pub fn derive_for_struct( .map(|(name, ty)| { let name = dhall_core::Label::from(name); constraints.push(ty.clone()); - (name, quote!(<#ty as dhall::Type>::get_type())) + (name, quote!(<#ty as dhall::StaticType>::get_type())) }) .collect(); let record = @@ -88,7 +88,7 @@ pub fn derive_for_enum( }; let ty = ty?; constraints.push(ty.clone()); - Ok((name, quote!(<#ty as dhall::Type>::get_type()))) + Ok((name, quote!(<#ty as dhall::StaticType>::get_type()))) }) .collect::>()?; @@ -136,7 +136,7 @@ pub fn derive_type_inner( let mut local_where_clause = orig_where_clause.clone(); local_where_clause .predicates - .push(parse_quote!(#ty: dhall::Type)); + .push(parse_quote!(#ty: dhall::StaticType)); let phantoms = generics.params.iter().map(|param| match param { syn::GenericParam::Type(syn::TypeParam { ident, .. }) => { quote!(#ident) @@ -156,12 +156,12 @@ pub fn derive_type_inner( // Ensure that all the fields have a Type impl let mut where_clause = orig_where_clause.clone(); for ty in constraints.iter() { - where_clause.predicates.push(parse_quote!(#ty: dhall::Type)); + where_clause.predicates.push(parse_quote!(#ty: dhall::StaticType)); } let ident = &input.ident; let tokens = quote! { - impl #impl_generics dhall::Type for #ident #ty_generics + impl #impl_generics dhall::StaticType for #ident #ty_generics #where_clause { fn get_type() -> dhall_core::DhallExpr { #(#assertions)* diff --git a/dhall_generator/src/lib.rs b/dhall_generator/src/lib.rs index f31faa4..08ce21e 100644 --- a/dhall_generator/src/lib.rs +++ b/dhall_generator/src/lib.rs @@ -21,7 +21,7 @@ pub fn subexpr(input: TokenStream) -> TokenStream { dhall_expr::subexpr(input) } -#[proc_macro_derive(Type)] +#[proc_macro_derive(StaticType)] pub fn derive_type(input: TokenStream) -> TokenStream { dhall_type::derive_type(input) } -- cgit v1.3.1 From 42d0f8100462f8a17a3ba1b86664310cdb71dfdc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 6 Apr 2019 17:55:43 +0200 Subject: Rename some modules --- dhall/src/dhall_type.rs | 77 -------------- dhall/src/lib.rs | 6 +- dhall/src/traits.rs | 77 ++++++++++++++ dhall/tests/dhall_type.rs | 53 ---------- dhall/tests/traits.rs | 53 ++++++++++ dhall_generator/src/derive.rs | 175 ++++++++++++++++++++++++++++++++ dhall_generator/src/dhall_expr.rs | 205 -------------------------------------- dhall_generator/src/dhall_type.rs | 173 -------------------------------- dhall_generator/src/lib.rs | 10 +- dhall_generator/src/quote.rs | 205 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 518 insertions(+), 516 deletions(-) delete mode 100644 dhall/src/dhall_type.rs create mode 100644 dhall/src/traits.rs delete mode 100644 dhall/tests/dhall_type.rs create mode 100644 dhall/tests/traits.rs create mode 100644 dhall_generator/src/derive.rs delete mode 100644 dhall_generator/src/dhall_expr.rs delete mode 100644 dhall_generator/src/dhall_type.rs create mode 100644 dhall_generator/src/quote.rs (limited to 'dhall/tests') diff --git a/dhall/src/dhall_type.rs b/dhall/src/dhall_type.rs deleted file mode 100644 index 64e07d9..0000000 --- a/dhall/src/dhall_type.rs +++ /dev/null @@ -1,77 +0,0 @@ -use dhall_core::*; -use dhall_generator::*; - -#[derive(Debug, Clone)] -pub enum ConversionError {} - -pub trait StaticType { - fn get_type() -> DhallExpr; - // fn as_dhall(&self) -> DhallExpr; - // fn from_dhall(e: DhallExpr) -> Result; -} - -impl StaticType for bool { - fn get_type() -> DhallExpr { - dhall_expr!(Bool) - } -} - -impl StaticType for Natural { - fn get_type() -> DhallExpr { - dhall_expr!(Natural) - } -} - -impl StaticType for Integer { - fn get_type() -> DhallExpr { - dhall_expr!(Integer) - } -} - -impl StaticType for String { - fn get_type() -> DhallExpr { - dhall_expr!(Text) - } -} - -impl StaticType for (A, B) { - fn get_type() -> DhallExpr { - let ta = A::get_type(); - let tb = B::get_type(); - dhall_expr!({ _1: ta, _2: tb }) - } -} - -impl StaticType for Option { - fn get_type() -> DhallExpr { - let t = T::get_type(); - dhall_expr!(Optional t) - } -} - -impl StaticType for Vec { - fn get_type() -> DhallExpr { - let t = T::get_type(); - dhall_expr!(List t) - } -} - -impl<'a, T: StaticType> StaticType for &'a T { - fn get_type() -> DhallExpr { - T::get_type() - } -} - -impl StaticType for std::marker::PhantomData { - fn get_type() -> DhallExpr { - dhall_expr!({}) - } -} - -impl StaticType for Result { - fn get_type() -> DhallExpr { - let tt = T::get_type(); - let te = E::get_type(); - dhall_expr!(< Ok: tt | Err: te>) - } -} diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index 5a155c8..7439312 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -10,14 +10,14 @@ mod normalize; pub use crate::normalize::*; pub mod binary; -mod dhall_type; pub mod imports; +mod traits; pub mod typecheck; -pub use crate::dhall_type::*; +pub use crate::imports::*; +pub use crate::traits::*; pub use dhall_generator::expr; pub use dhall_generator::subexpr; pub use dhall_generator::StaticType; -pub use crate::imports::*; // pub struct DhallExpr(dhall_core::DhallExpr); diff --git a/dhall/src/traits.rs b/dhall/src/traits.rs new file mode 100644 index 0000000..64e07d9 --- /dev/null +++ b/dhall/src/traits.rs @@ -0,0 +1,77 @@ +use dhall_core::*; +use dhall_generator::*; + +#[derive(Debug, Clone)] +pub enum ConversionError {} + +pub trait StaticType { + fn get_type() -> DhallExpr; + // fn as_dhall(&self) -> DhallExpr; + // fn from_dhall(e: DhallExpr) -> Result; +} + +impl StaticType for bool { + fn get_type() -> DhallExpr { + dhall_expr!(Bool) + } +} + +impl StaticType for Natural { + fn get_type() -> DhallExpr { + dhall_expr!(Natural) + } +} + +impl StaticType for Integer { + fn get_type() -> DhallExpr { + dhall_expr!(Integer) + } +} + +impl StaticType for String { + fn get_type() -> DhallExpr { + dhall_expr!(Text) + } +} + +impl StaticType for (A, B) { + fn get_type() -> DhallExpr { + let ta = A::get_type(); + let tb = B::get_type(); + dhall_expr!({ _1: ta, _2: tb }) + } +} + +impl StaticType for Option { + fn get_type() -> DhallExpr { + let t = T::get_type(); + dhall_expr!(Optional t) + } +} + +impl StaticType for Vec { + fn get_type() -> DhallExpr { + let t = T::get_type(); + dhall_expr!(List t) + } +} + +impl<'a, T: StaticType> StaticType for &'a T { + fn get_type() -> DhallExpr { + T::get_type() + } +} + +impl StaticType for std::marker::PhantomData { + fn get_type() -> DhallExpr { + dhall_expr!({}) + } +} + +impl StaticType for Result { + fn get_type() -> DhallExpr { + let tt = T::get_type(); + let te = E::get_type(); + dhall_expr!(< Ok: tt | Err: te>) + } +} diff --git a/dhall/tests/dhall_type.rs b/dhall/tests/dhall_type.rs deleted file mode 100644 index ac6b5e6..0000000 --- a/dhall/tests/dhall_type.rs +++ /dev/null @@ -1,53 +0,0 @@ -#![feature(proc_macro_hygiene)] -use dhall::StaticType; -use dhall_generator::dhall_expr; - -#[test] -fn test_dhall_type() { - assert_eq!(bool::get_type(), dhall_expr!(Bool)); - assert_eq!(String::get_type(), dhall_expr!(Text)); - assert_eq!( - <(bool, Option)>::get_type(), - dhall_expr!({ _1: Bool, _2: Optional Text }) - ); - - #[derive(dhall::StaticType)] - #[allow(dead_code)] - struct A { - field1: bool, - field2: Option, - } - assert_eq!( - ::get_type(), - dhall_expr!({ field1: Bool, field2: Optional Bool }) - ); - - #[derive(StaticType)] - #[allow(dead_code)] - struct B<'a, T: 'a> { - field1: &'a T, - field2: Option, - } - assert_eq!(>::get_type(), A::get_type()); - - #[derive(StaticType)] - #[allow(dead_code)] - struct C(T, Option); - assert_eq!(>::get_type(), <(bool, Option)>::get_type()); - - #[derive(StaticType)] - #[allow(dead_code)] - struct D(); - assert_eq!( - >::get_type(), - dhall_expr!({ _1: {}, _2: Optional Text }) - ); - - #[derive(StaticType)] - #[allow(dead_code)] - enum E { - A(T), - B(String), - }; - assert_eq!(>::get_type(), dhall_expr!(< A: Bool | B: Text >)); -} diff --git a/dhall/tests/traits.rs b/dhall/tests/traits.rs new file mode 100644 index 0000000..ac6b5e6 --- /dev/null +++ b/dhall/tests/traits.rs @@ -0,0 +1,53 @@ +#![feature(proc_macro_hygiene)] +use dhall::StaticType; +use dhall_generator::dhall_expr; + +#[test] +fn test_dhall_type() { + assert_eq!(bool::get_type(), dhall_expr!(Bool)); + assert_eq!(String::get_type(), dhall_expr!(Text)); + assert_eq!( + <(bool, Option)>::get_type(), + dhall_expr!({ _1: Bool, _2: Optional Text }) + ); + + #[derive(dhall::StaticType)] + #[allow(dead_code)] + struct A { + field1: bool, + field2: Option, + } + assert_eq!( + ::get_type(), + dhall_expr!({ field1: Bool, field2: Optional Bool }) + ); + + #[derive(StaticType)] + #[allow(dead_code)] + struct B<'a, T: 'a> { + field1: &'a T, + field2: Option, + } + assert_eq!(>::get_type(), A::get_type()); + + #[derive(StaticType)] + #[allow(dead_code)] + struct C(T, Option); + assert_eq!(>::get_type(), <(bool, Option)>::get_type()); + + #[derive(StaticType)] + #[allow(dead_code)] + struct D(); + assert_eq!( + >::get_type(), + dhall_expr!({ _1: {}, _2: Optional Text }) + ); + + #[derive(StaticType)] + #[allow(dead_code)] + enum E { + A(T), + B(String), + }; + assert_eq!(>::get_type(), dhall_expr!(< A: Bool | B: Text >)); +} diff --git a/dhall_generator/src/derive.rs b/dhall_generator/src/derive.rs new file mode 100644 index 0000000..159ff5c --- /dev/null +++ b/dhall_generator/src/derive.rs @@ -0,0 +1,175 @@ +extern crate proc_macro; +// use dhall_core::*; +use proc_macro::TokenStream; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; +use syn::Error; +use syn::{parse_quote, DeriveInput}; + +pub fn derive_type(input: TokenStream) -> TokenStream { + TokenStream::from(match derive_type_inner(input) { + Ok(tokens) => tokens, + Err(err) => err.to_compile_error(), + }) +} + +pub fn derive_for_struct( + data: &syn::DataStruct, + constraints: &mut Vec, +) -> Result { + let fields = match &data.fields { + syn::Fields::Named(fields) => fields + .named + .iter() + .map(|f| { + let name = f.ident.as_ref().unwrap().to_string(); + let ty = &f.ty; + (name, ty) + }) + .collect(), + syn::Fields::Unnamed(fields) => fields + .unnamed + .iter() + .enumerate() + .map(|(i, f)| { + let name = format!("_{}", i + 1); + let ty = &f.ty; + (name, ty) + }) + .collect(), + syn::Fields::Unit => vec![], + }; + let fields = fields + .into_iter() + .map(|(name, ty)| { + let name = dhall_core::Label::from(name); + constraints.push(ty.clone()); + (name, quote!(<#ty as dhall::StaticType>::get_type())) + }) + .collect(); + let record = + crate::quote::quote_exprf(dhall_core::ExprF::RecordType(fields)); + Ok(quote! { dhall_core::rc(#record) }) +} + +pub fn derive_for_enum( + data: &syn::DataEnum, + constraints: &mut Vec, +) -> Result { + let variants = data + .variants + .iter() + .map(|v| { + let name = dhall_core::Label::from(v.ident.to_string()); + let ty = match &v.fields { + syn::Fields::Unnamed(fields) if fields.unnamed.is_empty() => { + Err(Error::new( + v.span(), + "Nullary variants are not supported", + )) + } + syn::Fields::Unnamed(fields) if fields.unnamed.len() > 1 => { + Err(Error::new( + v.span(), + "Variants with more than one field are not supported", + )) + } + syn::Fields::Unnamed(fields) => { + Ok(&fields.unnamed.iter().next().unwrap().ty) + } + syn::Fields::Named(_) => Err(Error::new( + v.span(), + "Named variants are not supported", + )), + syn::Fields::Unit => Err(Error::new( + v.span(), + "Nullary variants are not supported", + )), + }; + let ty = ty?; + constraints.push(ty.clone()); + Ok((name, quote!(<#ty as dhall::StaticType>::get_type()))) + }) + .collect::>()?; + + let union = + crate::quote::quote_exprf(dhall_core::ExprF::UnionType(variants)); + Ok(quote! { dhall_core::rc(#union) }) +} + +pub fn derive_type_inner( + input: TokenStream, +) -> Result { + let input: DeriveInput = syn::parse_macro_input::parse(input)?; + + // List of types that must impl Type + let mut constraints = vec![]; + + let get_type = match &input.data { + syn::Data::Struct(data) => derive_for_struct(data, &mut constraints)?, + syn::Data::Enum(data) if data.variants.is_empty() => { + return Err(Error::new( + input.span(), + "Empty enums are not supported", + )) + } + syn::Data::Enum(data) => derive_for_enum(data, &mut constraints)?, + syn::Data::Union(x) => { + return Err(Error::new( + x.union_token.span(), + "Unions are not supported", + )) + } + }; + + let mut generics = input.generics.clone(); + generics.make_where_clause(); + let (impl_generics, ty_generics, orig_where_clause) = + generics.split_for_impl(); + let orig_where_clause = orig_where_clause.unwrap(); + + // Hygienic errors + let assertions = constraints.iter().enumerate().map(|(i, ty)| { + // Ensure that ty: Type, with an appropriate span + let assert_name = + syn::Ident::new(&format!("_AssertType{}", i), ty.span()); + let mut local_where_clause = orig_where_clause.clone(); + local_where_clause + .predicates + .push(parse_quote!(#ty: dhall::StaticType)); + let phantoms = generics.params.iter().map(|param| match param { + syn::GenericParam::Type(syn::TypeParam { ident, .. }) => { + quote!(#ident) + } + syn::GenericParam::Lifetime(syn::LifetimeDef { + lifetime, .. + }) => quote!(&#lifetime ()), + _ => unimplemented!(), + }); + quote_spanned! {ty.span()=> + struct #assert_name #impl_generics #local_where_clause { + _phantom: std::marker::PhantomData<(#(#phantoms),*)> + }; + } + }); + + // Ensure that all the fields have a Type impl + let mut where_clause = orig_where_clause.clone(); + for ty in constraints.iter() { + where_clause + .predicates + .push(parse_quote!(#ty: dhall::StaticType)); + } + + let ident = &input.ident; + let tokens = quote! { + impl #impl_generics dhall::StaticType for #ident #ty_generics + #where_clause { + fn get_type() -> dhall_core::DhallExpr { + #(#assertions)* + #get_type + } + } + }; + Ok(tokens) +} diff --git a/dhall_generator/src/dhall_expr.rs b/dhall_generator/src/dhall_expr.rs deleted file mode 100644 index d0c5733..0000000 --- a/dhall_generator/src/dhall_expr.rs +++ /dev/null @@ -1,205 +0,0 @@ -extern crate proc_macro; -use dhall_core::context::Context; -use dhall_core::*; -use proc_macro2::TokenStream; -use quote::quote; -use std::collections::BTreeMap; - -pub fn expr(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input_str = input.to_string(); - let expr: SubExpr = parse_expr(&input_str).unwrap(); - let no_import = - |_: &Import| -> X { panic!("Don't use import in dhall::expr!()") }; - let expr = expr.as_ref().map_embed(&no_import); - let output = quote_expr(&expr, &Context::new()); - output.into() -} - -pub fn subexpr(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input_str = input.to_string(); - let expr: SubExpr = parse_expr(&input_str).unwrap(); - let no_import = - |_: &Import| -> X { panic!("Don't use import in dhall::subexpr!()") }; - let expr = expr.as_ref().map_embed(&no_import); - let output = quote_subexpr(&rc(expr), &Context::new()); - output.into() -} - -// Returns an expression of type ExprF, where T is the -// type of the subexpressions after interpolation. -pub fn quote_exprf(expr: ExprF) -> TokenStream -where - TS: quote::ToTokens + std::fmt::Debug, -{ - let quote_map = |m: BTreeMap| -> TokenStream { - let entries = m.into_iter().map(|(k, v)| { - let k = quote_label(&k); - quote!(m.insert(#k, #v);) - }); - quote! { { - use std::collections::BTreeMap; - let mut m = BTreeMap::new(); - #( #entries )* - m - } } - }; - - let quote_vec = |e: Vec| -> TokenStream { - quote! { vec![ #(#e),* ] } - }; - - use dhall_core::ExprF::*; - match expr { - Var(_) => unreachable!(), - Pi(x, t, b) => { - let x = quote_label(&x); - quote! { dhall_core::ExprF::Pi(#x, #t, #b) } - } - Lam(x, t, b) => { - let x = quote_label(&x); - quote! { dhall_core::ExprF::Lam(#x, #t, #b) } - } - App(f, a) => { - let a = quote_vec(a); - quote! { dhall_core::ExprF::App(#f, #a) } - } - Const(c) => { - let c = quote_const(c); - quote! { dhall_core::ExprF::Const(#c) } - } - Builtin(b) => { - let b = quote_builtin(b); - quote! { dhall_core::ExprF::Builtin(#b) } - } - BinOp(o, a, b) => { - let o = quote_binop(o); - quote! { dhall_core::ExprF::BinOp(#o, #a, #b) } - } - NaturalLit(n) => { - quote! { dhall_core::ExprF::NaturalLit(#n) } - } - BoolLit(b) => { - quote! { dhall_core::ExprF::BoolLit(#b) } - } - EmptyOptionalLit(x) => { - quote! { dhall_core::ExprF::EmptyOptionalLit(#x) } - } - NEOptionalLit(x) => { - quote! { dhall_core::ExprF::NEOptionalLit(#x) } - } - EmptyListLit(t) => { - quote! { dhall_core::ExprF::EmptyListLit(#t) } - } - NEListLit(es) => { - let es = quote_vec(es); - quote! { dhall_core::ExprF::NEListLit(#es) } - } - RecordType(m) => { - let m = quote_map(m); - quote! { dhall_core::ExprF::RecordType(#m) } - } - RecordLit(m) => { - let m = quote_map(m); - quote! { dhall_core::ExprF::RecordLit(#m) } - } - UnionType(m) => { - let m = quote_map(m); - quote! { dhall_core::ExprF::UnionType(#m) } - } - e => unimplemented!("{:?}", e), - } -} - -// Returns an expression of type SubExpr<_, _>. Expects interpolated variables -// to be of type SubExpr<_, _>. -fn quote_subexpr( - expr: &SubExpr, - ctx: &Context, -) -> TokenStream { - use dhall_core::ExprF::*; - match expr.as_ref().map_ref( - |e| quote_subexpr(e, ctx), - |l, e| quote_subexpr(e, &ctx.insert(l.clone(), ())), - |_| unreachable!(), - |_| unreachable!(), - |l| l.clone(), - ) { - Var(V(ref s, n)) => { - match ctx.lookup(s, n) { - // Non-free variable; interpolates as itself - Some(()) => { - let s: String = s.into(); - let var = quote! { dhall_core::V(#s.into(), #n) }; - bx(quote! { dhall_core::ExprF::Var(#var) }) - } - // Free variable; interpolates as a rust variable - None => { - let s: String = s.into(); - // TODO: insert appropriate shifts ? - let v: TokenStream = s.parse().unwrap(); - quote! { { - let x: dhall_core::SubExpr<_, _> = #v.clone(); - x - } } - } - } - } - e => bx(quote_exprf(e)), - } -} - -// Returns an expression of type Expr<_, _>. Expects interpolated variables -// to be of type SubExpr<_, _>. -fn quote_expr(expr: &Expr, ctx: &Context) -> TokenStream { - use dhall_core::ExprF::*; - match expr.map_ref( - |e| quote_subexpr(e, ctx), - |l, e| quote_subexpr(e, &ctx.insert(l.clone(), ())), - |_| unreachable!(), - |_| unreachable!(), - |l| l.clone(), - ) { - Var(V(ref s, n)) => { - match ctx.lookup(s, n) { - // Non-free variable; interpolates as itself - Some(()) => { - let s: String = s.into(); - let var = quote! { dhall_core::V(#s.into(), #n) }; - quote! { dhall_core::ExprF::Var(#var) } - } - // Free variable; interpolates as a rust variable - None => { - let s: String = s.into(); - // TODO: insert appropriate shifts ? - let v: TokenStream = s.parse().unwrap(); - quote! { { - let x: dhall_core::SubExpr<_, _> = #v.clone(); - x.unroll() - } } - } - } - } - e => quote_exprf(e), - } -} - -fn quote_builtin(b: Builtin) -> TokenStream { - format!("dhall_core::Builtin::{:?}", b).parse().unwrap() -} - -fn quote_const(c: Const) -> TokenStream { - format!("dhall_core::Const::{:?}", c).parse().unwrap() -} - -fn quote_binop(b: BinOp) -> TokenStream { - format!("dhall_core::BinOp::{:?}", b).parse().unwrap() -} - -fn quote_label(l: &Label) -> TokenStream { - let l = String::from(l); - quote! { dhall_core::Label::from(#l) } -} - -fn bx(x: TokenStream) -> TokenStream { - quote! { dhall_core::bx(#x) } -} diff --git a/dhall_generator/src/dhall_type.rs b/dhall_generator/src/dhall_type.rs deleted file mode 100644 index 38c871d..0000000 --- a/dhall_generator/src/dhall_type.rs +++ /dev/null @@ -1,173 +0,0 @@ -extern crate proc_macro; -// use dhall_core::*; -use proc_macro::TokenStream; -use quote::{quote, quote_spanned}; -use syn::spanned::Spanned; -use syn::Error; -use syn::{parse_quote, DeriveInput}; - -pub fn derive_type(input: TokenStream) -> TokenStream { - TokenStream::from(match derive_type_inner(input) { - Ok(tokens) => tokens, - Err(err) => err.to_compile_error(), - }) -} - -pub fn derive_for_struct( - data: &syn::DataStruct, - constraints: &mut Vec, -) -> Result { - let fields = match &data.fields { - syn::Fields::Named(fields) => fields - .named - .iter() - .map(|f| { - let name = f.ident.as_ref().unwrap().to_string(); - let ty = &f.ty; - (name, ty) - }) - .collect(), - syn::Fields::Unnamed(fields) => fields - .unnamed - .iter() - .enumerate() - .map(|(i, f)| { - let name = format!("_{}", i + 1); - let ty = &f.ty; - (name, ty) - }) - .collect(), - syn::Fields::Unit => vec![], - }; - let fields = fields - .into_iter() - .map(|(name, ty)| { - let name = dhall_core::Label::from(name); - constraints.push(ty.clone()); - (name, quote!(<#ty as dhall::StaticType>::get_type())) - }) - .collect(); - let record = - crate::dhall_expr::quote_exprf(dhall_core::ExprF::RecordType(fields)); - Ok(quote! { dhall_core::rc(#record) }) -} - -pub fn derive_for_enum( - data: &syn::DataEnum, - constraints: &mut Vec, -) -> Result { - let variants = data - .variants - .iter() - .map(|v| { - let name = dhall_core::Label::from(v.ident.to_string()); - let ty = match &v.fields { - syn::Fields::Unnamed(fields) if fields.unnamed.is_empty() => { - Err(Error::new( - v.span(), - "Nullary variants are not supported", - )) - } - syn::Fields::Unnamed(fields) if fields.unnamed.len() > 1 => { - Err(Error::new( - v.span(), - "Variants with more than one field are not supported", - )) - } - syn::Fields::Unnamed(fields) => { - Ok(&fields.unnamed.iter().next().unwrap().ty) - } - syn::Fields::Named(_) => Err(Error::new( - v.span(), - "Named variants are not supported", - )), - syn::Fields::Unit => Err(Error::new( - v.span(), - "Nullary variants are not supported", - )), - }; - let ty = ty?; - constraints.push(ty.clone()); - Ok((name, quote!(<#ty as dhall::StaticType>::get_type()))) - }) - .collect::>()?; - - let union = - crate::dhall_expr::quote_exprf(dhall_core::ExprF::UnionType(variants)); - Ok(quote! { dhall_core::rc(#union) }) -} - -pub fn derive_type_inner( - input: TokenStream, -) -> Result { - let input: DeriveInput = syn::parse_macro_input::parse(input)?; - - // List of types that must impl Type - let mut constraints = vec![]; - - let get_type = match &input.data { - syn::Data::Struct(data) => derive_for_struct(data, &mut constraints)?, - syn::Data::Enum(data) if data.variants.is_empty() => { - return Err(Error::new( - input.span(), - "Empty enums are not supported", - )) - } - syn::Data::Enum(data) => derive_for_enum(data, &mut constraints)?, - syn::Data::Union(x) => { - return Err(Error::new( - x.union_token.span(), - "Unions are not supported", - )) - } - }; - - let mut generics = input.generics.clone(); - generics.make_where_clause(); - let (impl_generics, ty_generics, orig_where_clause) = - generics.split_for_impl(); - let orig_where_clause = orig_where_clause.unwrap(); - - // Hygienic errors - let assertions = constraints.iter().enumerate().map(|(i, ty)| { - // Ensure that ty: Type, with an appropriate span - let assert_name = - syn::Ident::new(&format!("_AssertType{}", i), ty.span()); - let mut local_where_clause = orig_where_clause.clone(); - local_where_clause - .predicates - .push(parse_quote!(#ty: dhall::StaticType)); - let phantoms = generics.params.iter().map(|param| match param { - syn::GenericParam::Type(syn::TypeParam { ident, .. }) => { - quote!(#ident) - } - syn::GenericParam::Lifetime(syn::LifetimeDef { - lifetime, .. - }) => quote!(&#lifetime ()), - _ => unimplemented!(), - }); - quote_spanned! {ty.span()=> - struct #assert_name #impl_generics #local_where_clause { - _phantom: std::marker::PhantomData<(#(#phantoms),*)> - }; - } - }); - - // Ensure that all the fields have a Type impl - let mut where_clause = orig_where_clause.clone(); - for ty in constraints.iter() { - where_clause.predicates.push(parse_quote!(#ty: dhall::StaticType)); - } - - let ident = &input.ident; - let tokens = quote! { - impl #impl_generics dhall::StaticType for #ident #ty_generics - #where_clause { - fn get_type() -> dhall_core::DhallExpr { - #(#assertions)* - #get_type - } - } - }; - Ok(tokens) -} diff --git a/dhall_generator/src/lib.rs b/dhall_generator/src/lib.rs index 08ce21e..b422834 100644 --- a/dhall_generator/src/lib.rs +++ b/dhall_generator/src/lib.rs @@ -1,7 +1,7 @@ extern crate proc_macro; -mod dhall_expr; -mod dhall_type; +mod derive; +mod quote; use proc_macro::TokenStream; @@ -13,15 +13,15 @@ pub fn dhall_expr(input: TokenStream) -> TokenStream { #[proc_macro] pub fn expr(input: TokenStream) -> TokenStream { - dhall_expr::expr(input) + quote::expr(input) } #[proc_macro] pub fn subexpr(input: TokenStream) -> TokenStream { - dhall_expr::subexpr(input) + quote::subexpr(input) } #[proc_macro_derive(StaticType)] pub fn derive_type(input: TokenStream) -> TokenStream { - dhall_type::derive_type(input) + derive::derive_type(input) } diff --git a/dhall_generator/src/quote.rs b/dhall_generator/src/quote.rs new file mode 100644 index 0000000..d0c5733 --- /dev/null +++ b/dhall_generator/src/quote.rs @@ -0,0 +1,205 @@ +extern crate proc_macro; +use dhall_core::context::Context; +use dhall_core::*; +use proc_macro2::TokenStream; +use quote::quote; +use std::collections::BTreeMap; + +pub fn expr(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input_str = input.to_string(); + let expr: SubExpr = parse_expr(&input_str).unwrap(); + let no_import = + |_: &Import| -> X { panic!("Don't use import in dhall::expr!()") }; + let expr = expr.as_ref().map_embed(&no_import); + let output = quote_expr(&expr, &Context::new()); + output.into() +} + +pub fn subexpr(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input_str = input.to_string(); + let expr: SubExpr = parse_expr(&input_str).unwrap(); + let no_import = + |_: &Import| -> X { panic!("Don't use import in dhall::subexpr!()") }; + let expr = expr.as_ref().map_embed(&no_import); + let output = quote_subexpr(&rc(expr), &Context::new()); + output.into() +} + +// Returns an expression of type ExprF, where T is the +// type of the subexpressions after interpolation. +pub fn quote_exprf(expr: ExprF) -> TokenStream +where + TS: quote::ToTokens + std::fmt::Debug, +{ + let quote_map = |m: BTreeMap| -> TokenStream { + let entries = m.into_iter().map(|(k, v)| { + let k = quote_label(&k); + quote!(m.insert(#k, #v);) + }); + quote! { { + use std::collections::BTreeMap; + let mut m = BTreeMap::new(); + #( #entries )* + m + } } + }; + + let quote_vec = |e: Vec| -> TokenStream { + quote! { vec![ #(#e),* ] } + }; + + use dhall_core::ExprF::*; + match expr { + Var(_) => unreachable!(), + Pi(x, t, b) => { + let x = quote_label(&x); + quote! { dhall_core::ExprF::Pi(#x, #t, #b) } + } + Lam(x, t, b) => { + let x = quote_label(&x); + quote! { dhall_core::ExprF::Lam(#x, #t, #b) } + } + App(f, a) => { + let a = quote_vec(a); + quote! { dhall_core::ExprF::App(#f, #a) } + } + Const(c) => { + let c = quote_const(c); + quote! { dhall_core::ExprF::Const(#c) } + } + Builtin(b) => { + let b = quote_builtin(b); + quote! { dhall_core::ExprF::Builtin(#b) } + } + BinOp(o, a, b) => { + let o = quote_binop(o); + quote! { dhall_core::ExprF::BinOp(#o, #a, #b) } + } + NaturalLit(n) => { + quote! { dhall_core::ExprF::NaturalLit(#n) } + } + BoolLit(b) => { + quote! { dhall_core::ExprF::BoolLit(#b) } + } + EmptyOptionalLit(x) => { + quote! { dhall_core::ExprF::EmptyOptionalLit(#x) } + } + NEOptionalLit(x) => { + quote! { dhall_core::ExprF::NEOptionalLit(#x) } + } + EmptyListLit(t) => { + quote! { dhall_core::ExprF::EmptyListLit(#t) } + } + NEListLit(es) => { + let es = quote_vec(es); + quote! { dhall_core::ExprF::NEListLit(#es) } + } + RecordType(m) => { + let m = quote_map(m); + quote! { dhall_core::ExprF::RecordType(#m) } + } + RecordLit(m) => { + let m = quote_map(m); + quote! { dhall_core::ExprF::RecordLit(#m) } + } + UnionType(m) => { + let m = quote_map(m); + quote! { dhall_core::ExprF::UnionType(#m) } + } + e => unimplemented!("{:?}", e), + } +} + +// Returns an expression of type SubExpr<_, _>. Expects interpolated variables +// to be of type SubExpr<_, _>. +fn quote_subexpr( + expr: &SubExpr, + ctx: &Context, +) -> TokenStream { + use dhall_core::ExprF::*; + match expr.as_ref().map_ref( + |e| quote_subexpr(e, ctx), + |l, e| quote_subexpr(e, &ctx.insert(l.clone(), ())), + |_| unreachable!(), + |_| unreachable!(), + |l| l.clone(), + ) { + Var(V(ref s, n)) => { + match ctx.lookup(s, n) { + // Non-free variable; interpolates as itself + Some(()) => { + let s: String = s.into(); + let var = quote! { dhall_core::V(#s.into(), #n) }; + bx(quote! { dhall_core::ExprF::Var(#var) }) + } + // Free variable; interpolates as a rust variable + None => { + let s: String = s.into(); + // TODO: insert appropriate shifts ? + let v: TokenStream = s.parse().unwrap(); + quote! { { + let x: dhall_core::SubExpr<_, _> = #v.clone(); + x + } } + } + } + } + e => bx(quote_exprf(e)), + } +} + +// Returns an expression of type Expr<_, _>. Expects interpolated variables +// to be of type SubExpr<_, _>. +fn quote_expr(expr: &Expr, ctx: &Context) -> TokenStream { + use dhall_core::ExprF::*; + match expr.map_ref( + |e| quote_subexpr(e, ctx), + |l, e| quote_subexpr(e, &ctx.insert(l.clone(), ())), + |_| unreachable!(), + |_| unreachable!(), + |l| l.clone(), + ) { + Var(V(ref s, n)) => { + match ctx.lookup(s, n) { + // Non-free variable; interpolates as itself + Some(()) => { + let s: String = s.into(); + let var = quote! { dhall_core::V(#s.into(), #n) }; + quote! { dhall_core::ExprF::Var(#var) } + } + // Free variable; interpolates as a rust variable + None => { + let s: String = s.into(); + // TODO: insert appropriate shifts ? + let v: TokenStream = s.parse().unwrap(); + quote! { { + let x: dhall_core::SubExpr<_, _> = #v.clone(); + x.unroll() + } } + } + } + } + e => quote_exprf(e), + } +} + +fn quote_builtin(b: Builtin) -> TokenStream { + format!("dhall_core::Builtin::{:?}", b).parse().unwrap() +} + +fn quote_const(c: Const) -> TokenStream { + format!("dhall_core::Const::{:?}", c).parse().unwrap() +} + +fn quote_binop(b: BinOp) -> TokenStream { + format!("dhall_core::BinOp::{:?}", b).parse().unwrap() +} + +fn quote_label(l: &Label) -> TokenStream { + let l = String::from(l); + quote! { dhall_core::Label::from(#l) } +} + +fn bx(x: TokenStream) -> TokenStream { + quote! { dhall_core::bx(#x) } +} -- cgit v1.3.1 From 396ec334bac1e8d10a2d2b2d683c93e3b2ff4d8d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 6 Apr 2019 20:04:04 +0200 Subject: Massage import loading into new API Closes #9 --- dhall/src/expr.rs | 30 ++++++++++----- dhall/src/imports.rs | 95 ++++++++++++++++++++++++++++------------------- dhall/tests/common/mod.rs | 9 ++++- dhall_core/src/core.rs | 39 +++++++++++++++++++ 4 files changed, 122 insertions(+), 51 deletions(-) (limited to 'dhall/tests') diff --git a/dhall/src/expr.rs b/dhall/src/expr.rs index 0d093cb..72633ea 100644 --- a/dhall/src/expr.rs +++ b/dhall/src/expr.rs @@ -1,17 +1,27 @@ +use crate::imports::ImportError; +use crate::imports::ImportRoot; use crate::typecheck::TypeError; use dhall_core::*; -pub struct Parsed(SubExpr); -pub struct Resolved(SubExpr); -pub struct Typed(SubExpr, Type); -pub struct Type(Box); -pub struct Normalized(SubExpr); +#[derive(Debug, Clone)] +pub struct Parsed(pub(crate) SubExpr, pub(crate) ImportRoot); +#[derive(Debug, Clone)] +pub struct Resolved(pub(crate) SubExpr); +#[derive(Debug, Clone)] +pub struct Typed(pub(crate) SubExpr, Type); +#[derive(Debug, Clone)] +pub struct Type(pub(crate) Box); +#[derive(Debug, Clone)] +pub struct Normalized(pub(crate) SubExpr); -// impl Parsed { -// pub fn resolve(self) -> Result { -// Ok(Resolved(crate::imports::resolve(self.0)?)) -// } -// } +impl Parsed { + pub fn resolve(self) -> Result { + crate::imports::resolve_expr(self, true) + } + pub fn resolve_no_imports(self) -> Result { + crate::imports::resolve_expr(self, false) + } +} impl Resolved { pub fn typecheck(self) -> Result> { let typ = Type(Box::new(Normalized(crate::typecheck::type_of( diff --git a/dhall/src/imports.rs b/dhall/src/imports.rs index 95cf6fa..bc38bb6 100644 --- a/dhall/src/imports.rs +++ b/dhall/src/imports.rs @@ -1,6 +1,7 @@ // use dhall_core::{Expr, FilePrefix, Import, ImportLocation, ImportMode, X}; use dhall_core::{Expr, Import, X}; // use std::path::Path; +use crate::expr::*; use dhall_core::*; use std::fmt; use std::fs::File; @@ -8,6 +9,34 @@ use std::io::Read; use std::path::Path; use std::path::PathBuf; +#[derive(Debug)] +pub enum ImportError { + ParseError(ParseError), + IOError(std::io::Error), + UnexpectedImportError(Import), +} +impl From for ImportError { + fn from(e: ParseError) -> Self { + ImportError::ParseError(e) + } +} +impl From for ImportError { + fn from(e: std::io::Error) -> Self { + ImportError::IOError(e) + } +} +impl fmt::Display for ImportError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use self::ImportError::*; + match self { + ParseError(e) => e.fmt(f), + IOError(e) => e.fmt(f), + UnexpectedImportError(e) => e.fmt(f), + } + } +} + +// Deprecated pub fn panic_imports(expr: &Expr) -> Expr { let no_import = |i: &Import| -> X { panic!("ahhh import: {:?}", i) }; expr.map_embed(&no_import) @@ -42,55 +71,43 @@ fn resolve_import( } } -#[derive(Debug)] -pub enum ImportError { - ParseError(ParseError), - IOError(std::io::Error), -} -impl From for ImportError { - fn from(e: ParseError) -> Self { - ImportError::ParseError(e) - } -} -impl From for ImportError { - fn from(e: std::io::Error) -> Self { - ImportError::IOError(e) - } -} -impl fmt::Display for ImportError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use self::ImportError::*; - match self { - ParseError(e) => e.fmt(f), - IOError(e) => e.fmt(f), +pub(crate) fn resolve_expr( + Parsed(expr, root): Parsed, + allow_imports: bool, +) -> Result { + let resolve = |import: &Import| -> Result, ImportError> { + if allow_imports { + let expr = resolve_import(import, &root)?; + Ok(expr.roll()) + } else { + Err(ImportError::UnexpectedImportError(import.clone())) } - } + }; + let expr = expr.as_ref().traverse_embed(&resolve)?; + Ok(Resolved(expr.squash_embed())) +} + +pub fn load_from_file(f: &Path) -> Result { + let mut buffer = String::new(); + File::open(f)?.read_to_string(&mut buffer)?; + let expr = parse_expr(&*buffer)?; + let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); + Ok(Parsed(expr, root)) } +// Deprecated pub fn load_dhall_file( f: &Path, resolve_imports: bool, ) -> Result, ImportError> { - let mut buffer = String::new(); - File::open(f)?.read_to_string(&mut buffer)?; - let expr = parse_expr(&*buffer)?; - let expr = if resolve_imports { - let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); - let resolve = |import: &Import| -> Expr { - resolve_import(import, &root).unwrap() - }; - expr.as_ref().map_embed(&resolve).squash_embed() - } else { - panic_imports(expr.as_ref()) - }; - Ok(expr) + let expr = load_from_file(f)?; + let expr = resolve_expr(expr, resolve_imports)?; + Ok(expr.0.unroll()) } +// Deprecated pub fn load_dhall_file_no_resolve_imports( f: &Path, ) -> Result { - let mut buffer = String::new(); - File::open(f)?.read_to_string(&mut buffer)?; - let expr = parse_expr(&*buffer)?; - Ok(expr) + Ok(load_from_file(f)?.0) } diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs index e748cf0..70b7d81 100644 --- a/dhall/tests/common/mod.rs +++ b/dhall/tests/common/mod.rs @@ -54,6 +54,12 @@ pub fn read_dhall_file_no_resolve_imports<'i>( load_dhall_file_no_resolve_imports(&PathBuf::from(file_path)) } +pub fn load_from_file_str<'i>( + file_path: &str, +) -> Result { + load_from_file(&PathBuf::from(file_path)) +} + pub fn run_test(base_path: &str, feature: Feature) { use self::Feature::*; let base_path_prefix = match feature { @@ -90,8 +96,7 @@ pub fn run_test(base_path: &str, feature: Feature) { } ParserFailure => { let file_path = base_path + ".dhall"; - let err = - read_dhall_file_no_resolve_imports(&file_path).unwrap_err(); + let err = load_from_file_str(&file_path).unwrap_err(); match err { ImportError::ParseError(_) => {} e => panic!("Expected parse error, got: {:?}", e), diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs index a56c5a3..d832cd5 100644 --- a/dhall_core/src/core.rs +++ b/dhall_core/src/core.rs @@ -285,6 +285,28 @@ impl Expr { self.map_shallow(recurse, |x| x.clone(), map_embed, |x| x.clone()) } + #[inline(always)] + pub fn traverse_embed( + &self, + map_embed: &F, + ) -> Result, Err> + where + S: Clone, + B: Clone, + F: Fn(&A) -> Result, + { + let recurse = |e: &SubExpr| -> Result, Err> { + Ok(e.as_ref().traverse_embed(map_embed)?.roll()) + }; + self.as_ref().traverse( + |e| recurse(e), + |_, e| recurse(e), + |x| Ok(S::clone(x)), + map_embed, + |x| Ok(Label::clone(x)), + ) + } + pub fn map_label(&self, map_label: &F) -> Self where A: Clone, @@ -319,6 +341,23 @@ impl Expr> { } } +impl Expr> { + pub fn squash_embed(&self) -> SubExpr { + match self.as_ref() { + ExprF::Embed(e) => e.clone(), + e => e + .map( + |e| e.as_ref().squash_embed(), + |_, e| e.as_ref().squash_embed(), + S::clone, + |_| unreachable!(), + Label::clone, + ) + .roll(), + } + } +} + impl ExprF { #[inline(always)] pub fn as_ref(&self) -> ExprF<&SE, &L, &N, &E> -- cgit v1.3.1 From 412d0fac51b7b51aabcb049e3d6ba52f3dda1529 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 6 Apr 2019 20:32:25 +0200 Subject: Move binary decoding to new API --- dhall/src/expr.rs | 22 +++++++++++++-------- dhall/src/imports.rs | 49 ++++++++++++++++++++++++++++++++++++++--------- dhall/src/lib.rs | 2 +- dhall/tests/common/mod.rs | 25 +++++++++++------------- 4 files changed, 66 insertions(+), 32 deletions(-) (limited to 'dhall/tests') diff --git a/dhall/src/expr.rs b/dhall/src/expr.rs index 72633ea..ae52e4d 100644 --- a/dhall/src/expr.rs +++ b/dhall/src/expr.rs @@ -1,27 +1,33 @@ -use crate::imports::ImportError; use crate::imports::ImportRoot; use crate::typecheck::TypeError; use dhall_core::*; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq)] pub struct Parsed(pub(crate) SubExpr, pub(crate) ImportRoot); -#[derive(Debug, Clone)] + +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Resolved(pub(crate) SubExpr); + #[derive(Debug, Clone)] pub struct Typed(pub(crate) SubExpr, Type); + #[derive(Debug, Clone)] pub struct Type(pub(crate) Box); + #[derive(Debug, Clone)] pub struct Normalized(pub(crate) SubExpr); -impl Parsed { - pub fn resolve(self) -> Result { - crate::imports::resolve_expr(self, true) +impl PartialEq for Parsed { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 } - pub fn resolve_no_imports(self) -> Result { - crate::imports::resolve_expr(self, false) +} +impl std::fmt::Display for Parsed { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + self.0.fmt(f) } } + impl Resolved { pub fn typecheck(self) -> Result> { let typ = Type(Box::new(Normalized(crate::typecheck::type_of( diff --git a/dhall/src/imports.rs b/dhall/src/imports.rs index bc38bb6..5d94b6a 100644 --- a/dhall/src/imports.rs +++ b/dhall/src/imports.rs @@ -1,6 +1,7 @@ // use dhall_core::{Expr, FilePrefix, Import, ImportLocation, ImportMode, X}; use dhall_core::{Expr, Import, X}; // use std::path::Path; +use crate::binary::DecodeError; use crate::expr::*; use dhall_core::*; use std::fmt; @@ -12,6 +13,7 @@ use std::path::PathBuf; #[derive(Debug)] pub enum ImportError { ParseError(ParseError), + BinaryDecodeError(DecodeError), IOError(std::io::Error), UnexpectedImportError(Import), } @@ -20,6 +22,11 @@ impl From for ImportError { ImportError::ParseError(e) } } +impl From for ImportError { + fn from(e: DecodeError) -> Self { + ImportError::BinaryDecodeError(e) + } +} impl From for ImportError { fn from(e: std::io::Error) -> Self { ImportError::IOError(e) @@ -30,6 +37,7 @@ impl fmt::Display for ImportError { use self::ImportError::*; match self { ParseError(e) => e.fmt(f), + BinaryDecodeError(_) => unimplemented!(), IOError(e) => e.fmt(f), UnexpectedImportError(e) => e.fmt(f), } @@ -71,7 +79,7 @@ fn resolve_import( } } -pub(crate) fn resolve_expr( +fn resolve_expr( Parsed(expr, root): Parsed, allow_imports: bool, ) -> Result { @@ -87,12 +95,35 @@ pub(crate) fn resolve_expr( Ok(Resolved(expr.squash_embed())) } -pub fn load_from_file(f: &Path) -> Result { - let mut buffer = String::new(); - File::open(f)?.read_to_string(&mut buffer)?; - let expr = parse_expr(&*buffer)?; - let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); - Ok(Parsed(expr, root)) +impl Parsed { + pub fn load_from_file(f: &Path) -> Result { + let mut buffer = String::new(); + File::open(f)?.read_to_string(&mut buffer)?; + let expr = parse_expr(&*buffer)?; + let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); + Ok(Parsed(expr, root)) + } + + pub fn load_from_str(s: &str) -> Result { + let expr = parse_expr(s)?; + let root = ImportRoot::LocalDir(std::env::current_dir()?); + Ok(Parsed(expr, root)) + } + + pub fn load_from_binary_file(f: &Path) -> Result { + let mut buffer = Vec::new(); + File::open(f)?.read_to_end(&mut buffer)?; + let expr = crate::binary::decode(&buffer)?; + let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); + Ok(Parsed(expr, root)) + } + + pub fn resolve(self) -> Result { + crate::imports::resolve_expr(self, true) + } + pub fn resolve_no_imports(self) -> Result { + crate::imports::resolve_expr(self, false) + } } // Deprecated @@ -100,7 +131,7 @@ pub fn load_dhall_file( f: &Path, resolve_imports: bool, ) -> Result, ImportError> { - let expr = load_from_file(f)?; + let expr = Parsed::load_from_file(f)?; let expr = resolve_expr(expr, resolve_imports)?; Ok(expr.0.unroll()) } @@ -109,5 +140,5 @@ pub fn load_dhall_file( pub fn load_dhall_file_no_resolve_imports( f: &Path, ) -> Result { - Ok(load_from_file(f)?.0) + Ok(Parsed::load_from_file(f)?.0) } diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index fee5ba8..28b43ba 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -9,7 +9,7 @@ mod normalize; pub use crate::normalize::*; -pub mod binary; +mod binary; pub mod imports; mod traits; pub mod typecheck; diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs index 70b7d81..861df63 100644 --- a/dhall/tests/common/mod.rs +++ b/dhall/tests/common/mod.rs @@ -44,20 +44,20 @@ pub enum Feature { TypeInferenceFailure, } -pub fn read_dhall_file<'i>(file_path: &str) -> Result, ImportError> { +fn read_dhall_file<'i>(file_path: &str) -> Result, ImportError> { load_dhall_file(&PathBuf::from(file_path), true) } -pub fn read_dhall_file_no_resolve_imports<'i>( +fn load_from_file_str<'i>( file_path: &str, -) -> Result { - load_dhall_file_no_resolve_imports(&PathBuf::from(file_path)) +) -> Result { + Parsed::load_from_file(&PathBuf::from(file_path)) } -pub fn load_from_file_str<'i>( +fn load_from_binary_file_str<'i>( file_path: &str, ) -> Result { - load_from_file(&PathBuf::from(file_path)) + Parsed::load_from_binary_file(&PathBuf::from(file_path)) } pub fn run_test(base_path: &str, feature: Feature) { @@ -77,21 +77,18 @@ pub fn run_test(base_path: &str, feature: Feature) { ParserSuccess => { let expr_file_path = base_path.clone() + "A.dhall"; let expected_file_path = base_path + "B.dhallb"; - let expr = read_dhall_file_no_resolve_imports(&expr_file_path) + let expr = load_from_file_str(&expr_file_path) .map_err(|e| println!("{}", e)) .unwrap(); - use std::fs::File; - use std::io::Read; - let mut file = File::open(expected_file_path).unwrap(); - let mut data = Vec::new(); - file.read_to_end(&mut data).unwrap(); - let expected = dhall::binary::decode(&data).unwrap(); + let expected = load_from_binary_file_str(&expected_file_path) + .map_err(|e| println!("{}", e)) + .unwrap(); assert_eq_pretty!(expr, expected); // Round-trip pretty-printer - let expr = parse_expr(&expr.to_string()).unwrap(); + let expr = Parsed::load_from_str(&expr.to_string()).unwrap(); assert_eq!(expr, expected); } ParserFailure => { -- cgit v1.3.1 From f93aee4dcf71c85b826244b3b57949ffbdb820c4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 6 Apr 2019 22:37:39 +0200 Subject: Add Sort type universe --- dhall/src/typecheck.rs | 9 ++++++--- dhall/tests/typecheck.rs | 12 ++++++------ dhall_core/src/core.rs | 1 + 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'dhall/tests') diff --git a/dhall/src/typecheck.rs b/dhall/src/typecheck.rs index d62fe5a..5457701 100644 --- a/dhall/src/typecheck.rs +++ b/dhall/src/typecheck.rs @@ -36,16 +36,19 @@ fn axiom(c: Const) -> Result> { use dhall_core::ExprF::*; match c { Type => Ok(Kind), - Kind => Err(TypeError::new(&Context::new(), rc(Const(Kind)), Untyped)), + Kind => Ok(Sort), + Sort => Err(TypeError::new(&Context::new(), rc(Const(Sort)), Untyped)), } } fn rule(a: Const, b: Const) -> Result { use dhall_core::Const::*; match (a, b) { - (Type, Kind) => Err(()), + (_, Type) => Ok(Type), (Kind, Kind) => Ok(Kind), - (Type, Type) | (Kind, Type) => Ok(Type), + (Sort, Sort) => Ok(Sort), + (Sort, Kind) => Ok(Sort), + _ => Err(()), } } diff --git a/dhall/tests/typecheck.rs b/dhall/tests/typecheck.rs index 367765c..6e05a87 100644 --- a/dhall/tests/typecheck.rs +++ b/dhall/tests/typecheck.rs @@ -7,11 +7,11 @@ macro_rules! tc_success { make_spec_test!(TypecheckSuccess, $name, $path); }; } -macro_rules! tc_failure { - ($name:ident, $path:expr) => { - make_spec_test!(TypecheckFailure, $name, $path); - }; -} +// macro_rules! tc_failure { +// ($name:ident, $path:expr) => { +// make_spec_test!(TypecheckFailure, $name, $path); +// }; +// } macro_rules! ti_success { ($name:ident, $path:expr) => { @@ -176,7 +176,7 @@ tc_success!(spec_typecheck_success_prelude_Text_concat_1, "prelude/Text/concat/1 // tc_failure!(spec_typecheck_failure_combineMixedRecords, "combineMixedRecords"); // tc_failure!(spec_typecheck_failure_duplicateFields, "duplicateFields"); -tc_failure!(spec_typecheck_failure_hurkensParadox, "hurkensParadox"); +// tc_failure!(spec_typecheck_failure_hurkensParadox, "hurkensParadox"); // ti_success!(spec_typeinference_success_simple_alternativesAreTypes, "simple/alternativesAreTypes"); // ti_success!(spec_typeinference_success_simple_kindParameter, "simple/kindParameter"); diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs index d832cd5..89506ec 100644 --- a/dhall_core/src/core.rs +++ b/dhall_core/src/core.rs @@ -68,6 +68,7 @@ impl From for f64 { pub enum Const { Type, Kind, + Sort, } /// Bound variable -- cgit v1.3.1 From da9937f623f2698adec50718e1e703958e837c85 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 7 Apr 2019 01:08:02 +0200 Subject: Put a Cow in Type --- dhall/src/expr.rs | 6 +- dhall/src/typecheck.rs | 148 +++++++++++++++++++++++++---------------------- dhall/tests/typecheck.rs | 6 +- 3 files changed, 84 insertions(+), 76 deletions(-) (limited to 'dhall/tests') diff --git a/dhall/src/expr.rs b/dhall/src/expr.rs index ad35645..75d7690 100644 --- a/dhall/src/expr.rs +++ b/dhall/src/expr.rs @@ -8,10 +8,10 @@ pub struct Parsed(pub(crate) SubExpr, pub(crate) ImportRoot); pub struct Resolved(pub(crate) SubExpr); #[derive(Debug, Clone)] -pub struct Typed(pub(crate) SubExpr, pub(crate) Type); +pub struct Typed(pub(crate) SubExpr, pub(crate) Type<'static>); #[derive(Debug, Clone)] -pub struct Type(pub(crate) TypeInternal); +pub struct Type<'a>(pub(crate) std::borrow::Cow<'a, TypeInternal>); #[derive(Debug, Clone)] pub(crate) enum TypeInternal { @@ -20,7 +20,7 @@ pub(crate) enum TypeInternal { } #[derive(Debug, Clone)] -pub struct Normalized(pub(crate) SubExpr, pub(crate) Type); +pub struct Normalized(pub(crate) SubExpr, pub(crate) Type<'static>); impl PartialEq for Parsed { fn eq(&self, other: &Self) -> bool { diff --git a/dhall/src/typecheck.rs b/dhall/src/typecheck.rs index 29ad6d4..a703821 100644 --- a/dhall/src/typecheck.rs +++ b/dhall/src/typecheck.rs @@ -6,6 +6,7 @@ use dhall_core; use dhall_core::context::Context; use dhall_core::*; use dhall_generator as dhall; +use std::borrow::Cow; use self::TypeMessage::*; @@ -22,11 +23,8 @@ impl Typed { fn into_expr(self) -> SubExpr { self.0 } - pub fn into_type(self) -> Type { - self.1 - } - pub fn get_type(&self) -> &Type { - &self.1 + pub fn get_type<'a>(&'a self) -> Type<'a> { + self.1.reborrow() } } impl Normalized { @@ -36,42 +34,47 @@ impl Normalized { fn into_expr(self) -> SubExpr { self.0 } - pub fn get_type(&self) -> &Type { - &self.1 + pub fn get_type<'a>(&'a self) -> Type<'a> { + self.1.reborrow() } - fn into_type(self) -> Type { - crate::expr::Type(TypeInternal::Expr(Box::new(self))) + fn into_type(self) -> Type<'static> { + crate::expr::Type(Cow::Owned(TypeInternal::Expr(Box::new(self)))) } } -impl Type { - fn as_expr(&self) -> &SubExpr { - &self.as_normalized().as_expr() +impl<'a> Type<'a> { + fn into_owned(self) -> Type<'static> { + Type(Cow::Owned(self.0.into_owned())) } - fn as_normalized(&self) -> &Normalized { - use TypeInternal::*; + fn reborrow<'b>(&'b self) -> Type<'b> { match &self.0 { - Expr(e) => &e, + Cow::Owned(x) => crate::expr::Type(Cow::Borrowed(x)), + Cow::Borrowed(x) => crate::expr::Type(Cow::Borrowed(x)), + } + } + fn as_expr(&'a self) -> &'a SubExpr { + use TypeInternal::*; + match self.0.as_ref() { + Expr(e) => e.as_expr(), Universe(_) => unimplemented!(), } } fn into_expr(self) -> SubExpr { use TypeInternal::*; - match self.0 { + match self.0.into_owned() { Expr(e) => e.into_expr(), Universe(_) => unimplemented!(), } } - pub fn get_type(&self) -> &Type { + pub fn get_type<'b>(&'b self) -> Type<'b> { use TypeInternal::*; - match &self.0 { + match self.0.as_ref() { Expr(e) => e.get_type(), - Universe(_) => unimplemented!(), - // Universe(n) => &Type(Universe(n+1)), + Universe(n) => crate::expr::Type(Cow::Owned(Universe(n + 1))), } } } -const TYPE_OF_SORT: Type = Type(TypeInternal::Universe(4)); +const TYPE_OF_SORT: Type<'static> = Type(Cow::Owned(TypeInternal::Universe(4))); fn rule(a: Const, b: Const) -> Result { use dhall_core::Const::*; @@ -160,7 +163,7 @@ fn prop_equal(eL0: &Type, eR0: &Type) -> bool { (_, _) => false, } } - match (&eL0.0, &eR0.0) { + match (&*eL0.0, &*eR0.0) { (TypeInternal::Universe(l), TypeInternal::Universe(r)) if r == l => { true } @@ -237,8 +240,8 @@ fn type_of_builtin(b: Builtin) -> Expr { } fn ensure_equal<'a, S, F1, F2>( - x: &'a Type, - y: &'a Type, + x: &Type<'a>, + y: &Type<'a>, mkerr: F1, mkmsg: F2, ) -> Result<(), TypeError> @@ -284,7 +287,7 @@ pub fn type_with( |ctx, x: SubExpr| Ok(type_with(ctx, x)?.normalize().into_type()); enum Ret { - RetType(crate::expr::Type), + RetType(crate::expr::Type<'static>), RetExpr(Expr), } use Ret::*; @@ -302,12 +305,13 @@ pub fn type_with( Ok(RetExpr(Pi( x.clone(), t2.as_expr().clone(), - b.into_type().into_expr(), + b.get_type().into_expr(), ))) } Pi(x, tA, tB) => { let tA = mktype(ctx, tA.clone())?; - let kA = ensure_const(tA.get_type(), InvalidInputType(tA.clone()))?; + let kA = + ensure_const(&tA.get_type(), InvalidInputType(tA.clone()))?; let ctx2 = ctx .insert(x.clone(), tA.as_expr().clone()) @@ -319,7 +323,7 @@ pub fn type_with( return Err(TypeError::new( &ctx2, e.clone(), - InvalidOutputType(tB.get_type().clone()), + InvalidOutputType(tB.get_type().into_owned()), )); } }; @@ -327,7 +331,7 @@ pub fn type_with( match rule(kA, kB) { Err(()) => Err(mkerr(NoDependentTypes( tA.clone(), - tB.get_type().clone(), + tB.get_type().into_owned(), ))), Ok(k) => Ok(RetExpr(Const(k))), } @@ -343,8 +347,8 @@ pub fn type_with( // Don't bother to provide a `let`-specific version of this error // message because this should never happen anyway let kR = ensure_const( - r.get_type().get_type(), - InvalidInputType(r.get_type().clone()), + &r.get_type().get_type(), + InvalidInputType(r.get_type().into_owned()), )?; let ctx2 = ctx.insert(f.clone(), r.get_type().as_expr().clone()); @@ -352,18 +356,18 @@ pub fn type_with( // Don't bother to provide a `let`-specific version of this error // message because this should never happen anyway let kB = ensure_const( - b.get_type().get_type(), - InvalidOutputType(b.get_type().clone()), + &b.get_type().get_type(), + InvalidOutputType(b.get_type().into_owned()), )?; if let Err(()) = rule(kR, kB) { return Err(mkerr(NoDependentLet( - r.into_type(), - b.into_type(), + r.get_type().into_owned(), + b.get_type().into_owned(), ))); } - Ok(RetType(b.get_type().clone())) + Ok(RetType(b.get_type().into_owned())) } _ => match e .as_ref() @@ -382,7 +386,7 @@ pub fn type_with( App(f, args) => { let mut iter = args.into_iter(); let mut seen_args: Vec> = vec![]; - let mut tf = f.get_type().clone(); + let mut tf = f.get_type().into_owned(); while let Some(a) = iter.next() { seen_args.push(a.as_expr().clone()); let (x, tx, tb) = match tf.as_expr().as_ref() { @@ -395,7 +399,7 @@ pub fn type_with( } }; let tx = mktype(ctx, tx.clone())?; - ensure_equal(&tx, a.get_type(), mkerr, || { + ensure_equal(&tx, &a.get_type(), mkerr, || { TypeMismatch( Typed( rc(App(f.as_expr().clone(), seen_args.clone())), @@ -414,37 +418,37 @@ pub fn type_with( } Annot(x, t) => { let t = t.normalize().into_type(); - ensure_equal(&t, x.get_type(), mkerr, || { + ensure_equal(&t, &x.get_type(), mkerr, || { AnnotMismatch(x.clone(), t.clone()) })?; - Ok(RetType(x.get_type().clone())) + Ok(RetType(x.get_type().into_owned())) } BoolIf(x, y, z) => { ensure_equal( - x.get_type(), + &x.get_type(), &mktype(ctx, rc(Builtin(Bool)))?, mkerr, || InvalidPredicate(x.clone()), )?; ensure_is_type( - y.get_type().get_type(), + &y.get_type().get_type(), IfBranchMustBeTerm(true, y.clone()), )?; ensure_is_type( - z.get_type().get_type(), + &z.get_type().get_type(), IfBranchMustBeTerm(false, z.clone()), )?; - ensure_equal(y.get_type(), z.get_type(), mkerr, || { + ensure_equal(&y.get_type(), &z.get_type(), mkerr, || { IfBranchMismatch(y.clone(), z.clone()) })?; - Ok(RetType(y.get_type().clone())) + Ok(RetType(y.get_type().into_owned())) } EmptyListLit(t) => { let t = t.normalize().into_type(); - ensure_is_type(t.get_type(), InvalidListType(t.clone()))?; + ensure_is_type(&t.get_type(), InvalidListType(t.clone()))?; let t = t.into_expr(); Ok(RetExpr(dhall::expr!(List t))) } @@ -452,35 +456,39 @@ pub fn type_with( let mut iter = xs.into_iter().enumerate(); let (_, x) = iter.next().unwrap(); ensure_is_type( - x.get_type().get_type(), - InvalidListType(x.get_type().clone()), + &x.get_type().get_type(), + InvalidListType(x.get_type().into_owned()), )?; for (i, y) in iter { - ensure_equal(x.get_type(), y.get_type(), mkerr, || { - InvalidListElement(i, x.get_type().clone(), y.clone()) + ensure_equal(&x.get_type(), &y.get_type(), mkerr, || { + InvalidListElement( + i, + x.get_type().into_owned(), + y.clone(), + ) })?; } - let t = x.into_type().into_expr(); + let t = x.get_type().into_expr(); Ok(RetExpr(dhall::expr!(List t))) } EmptyOptionalLit(t) => { let t = t.normalize().into_type(); - ensure_is_type(t.get_type(), InvalidOptionalType(t.clone()))?; + ensure_is_type(&t.get_type(), InvalidOptionalType(t.clone()))?; let t = t.into_expr(); Ok(RetExpr(dhall::expr!(Optional t))) } NEOptionalLit(x) => { ensure_is_type( - x.get_type().get_type(), - InvalidOptionalType(x.get_type().clone()), + &x.get_type().get_type(), + InvalidOptionalType(x.get_type().into_owned()), )?; - let t = x.into_type().into_expr(); + let t = x.get_type().into_expr(); Ok(RetExpr(dhall::expr!(Optional t))) } RecordType(kts) => { for (k, t) in kts { ensure_is_type( - t.get_type(), + &t.get_type(), InvalidFieldType(k.clone(), t.clone()), )?; } @@ -491,10 +499,10 @@ pub fn type_with( .into_iter() .map(|(k, v)| { ensure_is_type( - v.get_type().get_type(), + &v.get_type().get_type(), InvalidField(k.clone(), v.clone()), )?; - Ok((k.clone(), v.into_type().into_expr())) + Ok((k.clone(), v.get_type().into_expr())) }) .collect::>()?; Ok(RetExpr(RecordType(kts))) @@ -528,11 +536,11 @@ pub fn type_with( })), )?; - ensure_equal(l.get_type(), &t, mkerr, || { + ensure_equal(&l.get_type(), &t, mkerr, || { BinOpTypeMismatch(o, l.clone()) })?; - ensure_equal(r.get_type(), &t, mkerr, || { + ensure_equal(&r.get_type(), &t, mkerr, || { BinOpTypeMismatch(o, r.clone()) })?; @@ -553,7 +561,7 @@ pub fn type_with( /// will fail. pub fn type_of(e: SubExpr) -> Result, TypeError> { let ctx = Context::new(); - type_with(&ctx, e).map(|e| e.into_type().into_expr()) + type_with(&ctx, e).map(|e| e.get_type().into_expr()) } pub fn type_of_(e: SubExpr) -> Result> { @@ -565,15 +573,15 @@ pub fn type_of_(e: SubExpr) -> Result> { #[derive(Debug)] pub enum TypeMessage { UnboundVariable, - InvalidInputType(Type), - InvalidOutputType(Type), + InvalidInputType(Type<'static>), + InvalidOutputType(Type<'static>), NotAFunction(Typed), - TypeMismatch(Typed, Type, Typed), - AnnotMismatch(Typed, Type), + TypeMismatch(Typed, Type<'static>, Typed), + AnnotMismatch(Typed, Type<'static>), Untyped, - InvalidListElement(usize, Type, Typed), - InvalidListType(Type), - InvalidOptionalType(Type), + InvalidListElement(usize, Type<'static>, Typed), + InvalidListType(Type<'static>), + InvalidOptionalType(Type<'static>), InvalidPredicate(Typed), IfBranchMismatch(Typed, Typed), IfBranchMustBeTerm(bool, Typed), @@ -584,8 +592,8 @@ pub enum TypeMessage { NotARecord(Label, Typed), MissingField(Label, Typed), BinOpTypeMismatch(BinOp, Typed), - NoDependentLet(Type, Type), - NoDependentTypes(Type, Type), + NoDependentLet(Type<'static>, Type<'static>), + NoDependentTypes(Type<'static>, Type<'static>), MustCombineARecord(SubExpr, SubExpr), } diff --git a/dhall/tests/typecheck.rs b/dhall/tests/typecheck.rs index 6e05a87..56a8823 100644 --- a/dhall/tests/typecheck.rs +++ b/dhall/tests/typecheck.rs @@ -87,8 +87,8 @@ tc_success!(spec_typecheck_success_prelude_List_replicate_0, "prelude/List/repli tc_success!(spec_typecheck_success_prelude_List_replicate_1, "prelude/List/replicate/1"); tc_success!(spec_typecheck_success_prelude_List_reverse_0, "prelude/List/reverse/0"); tc_success!(spec_typecheck_success_prelude_List_reverse_1, "prelude/List/reverse/1"); -tc_success!(spec_typecheck_success_prelude_List_shifted_0, "prelude/List/shifted/0"); -tc_success!(spec_typecheck_success_prelude_List_shifted_1, "prelude/List/shifted/1"); +// tc_success!(spec_typecheck_success_prelude_List_shifted_0, "prelude/List/shifted/0"); +// tc_success!(spec_typecheck_success_prelude_List_shifted_1, "prelude/List/shifted/1"); tc_success!(spec_typecheck_success_prelude_List_unzip_0, "prelude/List/unzip/0"); tc_success!(spec_typecheck_success_prelude_List_unzip_1, "prelude/List/unzip/1"); tc_success!(spec_typecheck_success_prelude_Monoid_00, "prelude/Monoid/00"); @@ -96,7 +96,7 @@ tc_success!(spec_typecheck_success_prelude_Monoid_01, "prelude/Monoid/01"); tc_success!(spec_typecheck_success_prelude_Monoid_02, "prelude/Monoid/02"); tc_success!(spec_typecheck_success_prelude_Monoid_03, "prelude/Monoid/03"); tc_success!(spec_typecheck_success_prelude_Monoid_04, "prelude/Monoid/04"); -tc_success!(spec_typecheck_success_prelude_Monoid_05, "prelude/Monoid/05"); +// tc_success!(spec_typecheck_success_prelude_Monoid_05, "prelude/Monoid/05"); tc_success!(spec_typecheck_success_prelude_Monoid_06, "prelude/Monoid/06"); tc_success!(spec_typecheck_success_prelude_Monoid_07, "prelude/Monoid/07"); tc_success!(spec_typecheck_success_prelude_Monoid_08, "prelude/Monoid/08"); -- cgit v1.3.1 From 619290e208f59bb15fc4f9d4b6dae2c19bb7b711 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 7 Apr 2019 01:41:08 +0200 Subject: Augment stack size for typecheck tests --- dhall/src/typecheck.rs | 12 ++++++++++++ dhall/tests/common/mod.rs | 20 +++++++++++++++----- dhall/tests/typecheck.rs | 6 +++--- 3 files changed, 30 insertions(+), 8 deletions(-) (limited to 'dhall/tests') diff --git a/dhall/src/typecheck.rs b/dhall/src/typecheck.rs index becabbd..fe9f68c 100644 --- a/dhall/src/typecheck.rs +++ b/dhall/src/typecheck.rs @@ -17,40 +17,50 @@ impl Resolved { } } impl Typed { + #[inline(always)] fn as_expr(&self) -> &SubExpr { &self.0 } + #[inline(always)] fn into_expr(self) -> SubExpr { self.0 } + #[inline(always)] pub fn get_type<'a>(&'a self) -> Type<'a> { self.1.reborrow() } } impl Normalized { + #[inline(always)] fn as_expr(&self) -> &SubExpr { &self.0 } + #[inline(always)] fn into_expr(self) -> SubExpr { self.0 } + #[inline(always)] pub fn get_type<'a>(&'a self) -> Type<'a> { self.1.reborrow() } + #[inline(always)] fn into_type(self) -> Type<'static> { crate::expr::Type(Cow::Owned(TypeInternal::Expr(Box::new(self)))) } } impl<'a> Type<'a> { + #[inline(always)] fn into_owned(self) -> Type<'static> { Type(Cow::Owned(self.0.into_owned())) } + #[inline(always)] fn reborrow<'b>(&'b self) -> Type<'b> { match &self.0 { Cow::Owned(x) => crate::expr::Type(Cow::Borrowed(x)), Cow::Borrowed(x) => crate::expr::Type(Cow::Borrowed(x)), } } + #[inline(always)] fn as_expr(&'a self) -> Result<&'a SubExpr, TypeError> { use TypeInternal::*; match self.0.as_ref() { @@ -62,6 +72,7 @@ impl<'a> Type<'a> { )), } } + #[inline(always)] fn into_expr(self) -> Result, TypeError> { use TypeInternal::*; match self.0.into_owned() { @@ -73,6 +84,7 @@ impl<'a> Type<'a> { )), } } + #[inline(always)] pub fn get_type<'b>(&'b self) -> Type<'b> { use TypeInternal::*; match self.0.as_ref() { diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs index 861df63..3c2fc3c 100644 --- a/dhall/tests/common/mod.rs +++ b/dhall/tests/common/mod.rs @@ -113,11 +113,21 @@ pub fn run_test(base_path: &str, feature: Feature) { typecheck::type_of(expr).unwrap_err(); } TypecheckSuccess => { - let expr_file_path = base_path.clone() + "A.dhall"; - let expected_file_path = base_path + "B.dhall"; - let expr = rc(read_dhall_file(&expr_file_path).unwrap()); - let expected = rc(read_dhall_file(&expected_file_path).unwrap()); - typecheck::type_of(rc(ExprF::Annot(expr, expected))).unwrap(); + // Many tests stack overflow in debug mode + std::thread::Builder::new() + .stack_size(4 * 1024 * 1024) + .spawn(|| { + let expr_file_path = base_path.clone() + "A.dhall"; + let expected_file_path = base_path + "B.dhall"; + let expr = rc(read_dhall_file(&expr_file_path).unwrap()); + let expected = + rc(read_dhall_file(&expected_file_path).unwrap()); + typecheck::type_of(rc(ExprF::Annot(expr, expected))) + .unwrap(); + }) + .unwrap() + .join() + .unwrap(); } TypeInferenceFailure => { let file_path = base_path + ".dhall"; diff --git a/dhall/tests/typecheck.rs b/dhall/tests/typecheck.rs index 56a8823..6e05a87 100644 --- a/dhall/tests/typecheck.rs +++ b/dhall/tests/typecheck.rs @@ -87,8 +87,8 @@ tc_success!(spec_typecheck_success_prelude_List_replicate_0, "prelude/List/repli tc_success!(spec_typecheck_success_prelude_List_replicate_1, "prelude/List/replicate/1"); tc_success!(spec_typecheck_success_prelude_List_reverse_0, "prelude/List/reverse/0"); tc_success!(spec_typecheck_success_prelude_List_reverse_1, "prelude/List/reverse/1"); -// tc_success!(spec_typecheck_success_prelude_List_shifted_0, "prelude/List/shifted/0"); -// tc_success!(spec_typecheck_success_prelude_List_shifted_1, "prelude/List/shifted/1"); +tc_success!(spec_typecheck_success_prelude_List_shifted_0, "prelude/List/shifted/0"); +tc_success!(spec_typecheck_success_prelude_List_shifted_1, "prelude/List/shifted/1"); tc_success!(spec_typecheck_success_prelude_List_unzip_0, "prelude/List/unzip/0"); tc_success!(spec_typecheck_success_prelude_List_unzip_1, "prelude/List/unzip/1"); tc_success!(spec_typecheck_success_prelude_Monoid_00, "prelude/Monoid/00"); @@ -96,7 +96,7 @@ tc_success!(spec_typecheck_success_prelude_Monoid_01, "prelude/Monoid/01"); tc_success!(spec_typecheck_success_prelude_Monoid_02, "prelude/Monoid/02"); tc_success!(spec_typecheck_success_prelude_Monoid_03, "prelude/Monoid/03"); tc_success!(spec_typecheck_success_prelude_Monoid_04, "prelude/Monoid/04"); -// tc_success!(spec_typecheck_success_prelude_Monoid_05, "prelude/Monoid/05"); +tc_success!(spec_typecheck_success_prelude_Monoid_05, "prelude/Monoid/05"); tc_success!(spec_typecheck_success_prelude_Monoid_06, "prelude/Monoid/06"); tc_success!(spec_typecheck_success_prelude_Monoid_07, "prelude/Monoid/07"); tc_success!(spec_typecheck_success_prelude_Monoid_08, "prelude/Monoid/08"); -- cgit v1.3.1 From c461548c32f8cb3ee2db5ade88ae4f91b3838ab5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 7 Apr 2019 11:09:57 +0200 Subject: Avoid constructing exprs manually when possible --- dhall/src/typecheck.rs | 38 ++++++++++++++++++++------------------ dhall/tests/common/mod.rs | 2 +- dhall/tests/normalization.rs | 1 + dhall/tests/parser.rs | 1 + dhall/tests/typecheck.rs | 1 + dhall_core/src/parser.rs | 2 ++ dhall_generator/src/quote.rs | 3 +++ 7 files changed, 29 insertions(+), 19 deletions(-) (limited to 'dhall/tests') diff --git a/dhall/src/typecheck.rs b/dhall/src/typecheck.rs index 3815f9f..5be43cf 100644 --- a/dhall/src/typecheck.rs +++ b/dhall/src/typecheck.rs @@ -370,7 +370,9 @@ pub fn type_with( } Let(f, mt, r, b) => { let r = if let Some(t) = mt { - rc(Annot(SubExpr::clone(r), SubExpr::clone(t))) + let r = SubExpr::clone(r); + let t = SubExpr::clone(t); + dhall::subexpr!(r: t) } else { SubExpr::clone(r) }; @@ -409,8 +411,8 @@ pub fn type_with( Lam(_, _, _) => unreachable!(), Pi(_, _, _) => unreachable!(), Let(_, _, _, _) => unreachable!(), - Const(Type) => Ok(RetExpr(Const(Kind))), - Const(Kind) => Ok(RetExpr(Const(Sort))), + Const(Type) => Ok(RetExpr(dhall::expr!(Kind))), + Const(Kind) => Ok(RetExpr(dhall::expr!(Sort))), Const(Sort) => Ok(RetType(TYPE_OF_SORT)), Var(V(x, n)) => match ctx.lookup(&x, n) { Some(e) => Ok(RetExpr(e.unroll())), @@ -531,7 +533,7 @@ pub fn type_with( InvalidFieldType(k.clone(), t.clone()), )?; } - Ok(RetExpr(Const(Type))) + Ok(RetExpr(dhall::expr!(Type))) } RecordLit(kvs) => { let kts = kvs @@ -554,25 +556,25 @@ pub fn type_with( _ => Err(mkerr(NotARecord(x.clone(), r.clone()))), }, Builtin(b) => Ok(RetExpr(type_of_builtin(b))), - BoolLit(_) => Ok(RetExpr(Builtin(Bool))), - NaturalLit(_) => Ok(RetExpr(Builtin(Natural))), - IntegerLit(_) => Ok(RetExpr(Builtin(Integer))), - DoubleLit(_) => Ok(RetExpr(Builtin(Double))), + BoolLit(_) => Ok(RetExpr(dhall::expr!(Bool))), + NaturalLit(_) => Ok(RetExpr(dhall::expr!(Natural))), + IntegerLit(_) => Ok(RetExpr(dhall::expr!(Integer))), + DoubleLit(_) => Ok(RetExpr(dhall::expr!(Double))), // TODO: check type of interpolations - TextLit(_) => Ok(RetExpr(Builtin(Text))), + TextLit(_) => Ok(RetExpr(dhall::expr!(Text))), BinOp(o, l, r) => { let t = mktype( ctx, - rc(Builtin(match o { - BoolAnd => Bool, - BoolOr => Bool, - BoolEQ => Bool, - BoolNE => Bool, - NaturalPlus => Natural, - NaturalTimes => Natural, - TextAppend => Text, + match o { + BoolAnd => dhall::subexpr!(Bool), + BoolOr => dhall::subexpr!(Bool), + BoolEQ => dhall::subexpr!(Bool), + BoolNE => dhall::subexpr!(Bool), + NaturalPlus => dhall::subexpr!(Natural), + NaturalTimes => dhall::subexpr!(Natural), + TextAppend => dhall::subexpr!(Text), _ => panic!("Unimplemented typecheck case: {:?}", e), - })), + }, )?; ensure_equal(&l.get_type(), &t, mkerr, || { diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs index 3c2fc3c..fc5aa5b 100644 --- a/dhall/tests/common/mod.rs +++ b/dhall/tests/common/mod.rs @@ -122,7 +122,7 @@ pub fn run_test(base_path: &str, feature: Feature) { let expr = rc(read_dhall_file(&expr_file_path).unwrap()); let expected = rc(read_dhall_file(&expected_file_path).unwrap()); - typecheck::type_of(rc(ExprF::Annot(expr, expected))) + typecheck::type_of(dhall::subexpr!(expr: expected)) .unwrap(); }) .unwrap() diff --git a/dhall/tests/normalization.rs b/dhall/tests/normalization.rs index 5ecc02f..a36a6ac 100644 --- a/dhall/tests/normalization.rs +++ b/dhall/tests/normalization.rs @@ -1,3 +1,4 @@ +#![feature(proc_macro_hygiene)] #![feature(custom_inner_attributes)] #![rustfmt::skip] mod common; diff --git a/dhall/tests/parser.rs b/dhall/tests/parser.rs index 0b5e2d6..3969dc9 100644 --- a/dhall/tests/parser.rs +++ b/dhall/tests/parser.rs @@ -1,3 +1,4 @@ +#![feature(proc_macro_hygiene)] #![feature(custom_inner_attributes)] #![rustfmt::skip] mod common; diff --git a/dhall/tests/typecheck.rs b/dhall/tests/typecheck.rs index 6e05a87..8d72313 100644 --- a/dhall/tests/typecheck.rs +++ b/dhall/tests/typecheck.rs @@ -1,3 +1,4 @@ +#![feature(proc_macro_hygiene)] #![feature(custom_inner_attributes)] #![rustfmt::skip] mod common; diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index 67bcf77..41a2ce7 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -764,6 +764,7 @@ make_parser! { "False" => BoolLit(false), "Type" => Const(crate::Const::Type), "Kind" => Const(crate::Const::Kind), + "Sort" => Const(crate::Const::Sort), _ => Var(V(l, idx)), } } @@ -777,6 +778,7 @@ make_parser! { "False" => BoolLit(false), "Type" => Const(crate::Const::Type), "Kind" => Const(crate::Const::Kind), + "Sort" => Const(crate::Const::Sort), _ => Var(V(l, 0)), } } diff --git a/dhall_generator/src/quote.rs b/dhall_generator/src/quote.rs index d0c5733..8fce89d 100644 --- a/dhall_generator/src/quote.rs +++ b/dhall_generator/src/quote.rs @@ -63,6 +63,9 @@ where let a = quote_vec(a); quote! { dhall_core::ExprF::App(#f, #a) } } + Annot(x, t) => { + quote! { dhall_core::ExprF::Annot(#x, #t) } + } Const(c) => { let c = quote_const(c); quote! { dhall_core::ExprF::Const(#c) } -- cgit v1.3.1 From 4bebcd96b6e76b9b8ae7877af91d2ae571e617a9 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 7 Apr 2019 16:45:30 +0200 Subject: Restrict public API Closes #20 --- dhall/src/expr.rs | 48 ++++++++++++++++++++++-------------- dhall/src/imports.rs | 15 +---------- dhall/src/lib.rs | 12 ++++----- dhall/src/main.rs | 20 +++++++-------- dhall/src/normalize.rs | 8 ++++-- dhall/src/typecheck.rs | 9 ++++--- dhall/tests/common/mod.rs | 63 +++++++++++++++++++++++++++++++++++------------ 7 files changed, 104 insertions(+), 71 deletions(-) (limited to 'dhall/tests') diff --git a/dhall/src/expr.rs b/dhall/src/expr.rs index 555db2f..7baf628 100644 --- a/dhall/src/expr.rs +++ b/dhall/src/expr.rs @@ -1,34 +1,46 @@ use crate::imports::ImportRoot; use dhall_core::*; +macro_rules! derive_other_traits { + ($ty:ident) => { + impl std::cmp::PartialEq for $ty { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl std::fmt::Display for $ty { + fn fmt( + &self, + f: &mut std::fmt::Formatter, + ) -> Result<(), std::fmt::Error> { + self.0.fmt(f) + } + } + }; +} + #[derive(Debug, Clone, Eq)] pub struct Parsed(pub(crate) SubExpr, pub(crate) ImportRoot); +derive_other_traits!(Parsed); -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Eq)] pub struct Resolved(pub(crate) SubExpr); +derive_other_traits!(Resolved); -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq)] pub struct Typed(pub(crate) SubExpr, pub(crate) Type); +derive_other_traits!(Typed); + +#[derive(Debug, Clone, Eq)] +pub struct Normalized(pub(crate) SubExpr, pub(crate) Type); +derive_other_traits!(Normalized); -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Type(pub(crate) TypeInternal); -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum TypeInternal { Expr(Box), Untyped, } - -#[derive(Debug, Clone)] -pub struct Normalized(pub(crate) SubExpr, pub(crate) Type); - -impl PartialEq for Parsed { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} -impl std::fmt::Display for Parsed { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - self.0.fmt(f) - } -} diff --git a/dhall/src/imports.rs b/dhall/src/imports.rs index 5d94b6a..fdde8c3 100644 --- a/dhall/src/imports.rs +++ b/dhall/src/imports.rs @@ -44,12 +44,6 @@ impl fmt::Display for ImportError { } } -// Deprecated -pub fn panic_imports(expr: &Expr) -> Expr { - let no_import = |i: &Import| -> X { panic!("ahhh import: {:?}", i) }; - expr.map_embed(&no_import) -} - /// A root from which to resolve relative imports. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ImportRoot { @@ -121,7 +115,7 @@ impl Parsed { pub fn resolve(self) -> Result { crate::imports::resolve_expr(self, true) } - pub fn resolve_no_imports(self) -> Result { + pub fn skip_resolve(self) -> Result { crate::imports::resolve_expr(self, false) } } @@ -135,10 +129,3 @@ pub fn load_dhall_file( let expr = resolve_expr(expr, resolve_imports)?; Ok(expr.0.unroll()) } - -// Deprecated -pub fn load_dhall_file_no_resolve_imports( - f: &Path, -) -> Result { - Ok(Parsed::load_from_file(f)?.0) -} diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index 28b43ba..f00e5b6 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -7,16 +7,14 @@ clippy::many_single_char_names )] -mod normalize; -pub use crate::normalize::*; mod binary; -pub mod imports; -mod traits; +mod imports; +mod normalize; +pub mod traits; pub mod typecheck; -pub use crate::imports::*; -pub use crate::traits::*; +pub use crate::imports::{load_dhall_file, ImportError}; +pub use crate::traits::StaticType; pub use dhall_generator::expr; pub use dhall_generator::subexpr; pub use dhall_generator::StaticType; pub mod expr; -pub use crate::expr::*; diff --git a/dhall/src/main.rs b/dhall/src/main.rs index 77f558c..2881d5a 100644 --- a/dhall/src/main.rs +++ b/dhall/src/main.rs @@ -2,9 +2,6 @@ use std::error::Error; use std::io::{self, Read}; use term_painter::ToStyle; -use dhall::*; -use dhall_core::*; - const ERROR_STYLE: term_painter::Color = term_painter::Color::Red; const BOLD: term_painter::Attr = term_painter::Attr::Bold; @@ -57,17 +54,19 @@ fn print_error(message: &str, source: &str, start: usize, end: usize) { fn main() { let mut buffer = String::new(); io::stdin().read_to_string(&mut buffer).unwrap(); - let expr = match parse_expr(&buffer) { - Ok(e) => e, + + let expr = match dhall::expr::Parsed::load_from_str(&buffer) { + Ok(expr) => expr, Err(e) => { print_error(&format!("Parse error {}", e), &buffer, 0, 0); return; } }; - let expr: SubExpr<_, _> = rc(imports::panic_imports(expr.as_ref())); + let expr = expr.resolve().unwrap(); - let type_expr = match typecheck::type_of(expr.clone()) { + let expr = match expr.typecheck() { + Ok(expr) => expr, Err(e) => { let explain = ::std::env::args().any(|s| s == "--explain"); if !explain { @@ -84,10 +83,9 @@ fn main() { // FIXME Print source position return; } - Ok(type_expr) => type_expr, }; - println!("{}", type_expr); - println!(); - println!("{}", normalize(expr)); + let expr = expr.normalize(); + + println!("{}", expr); } diff --git a/dhall/src/normalize.rs b/dhall/src/normalize.rs index f9633fb..c07d3cb 100644 --- a/dhall/src/normalize.rs +++ b/dhall/src/normalize.rs @@ -8,6 +8,10 @@ impl Typed { pub fn normalize(self) -> Normalized { Normalized(normalize(self.0), self.1) } + /// Pretends this expression is normalized. Use with care. + pub fn skip_normalize(self) -> Normalized { + Normalized(self.0, self.1) + } } fn apply_builtin(b: Builtin, args: &Vec>) -> WhatNext @@ -209,7 +213,7 @@ enum WhatNext<'a, S, A> { DoneAsIs, } -pub fn normalize_ref(expr: &Expr) -> Expr +fn normalize_ref(expr: &Expr) -> Expr where S: fmt::Debug + Clone, A: fmt::Debug + Clone, @@ -313,7 +317,7 @@ where /// However, `normalize` will not fail if the expression is ill-typed and will /// leave ill-typed sub-expressions unevaluated. /// -pub fn normalize(e: SubExpr) -> SubExpr +fn normalize(e: SubExpr) -> SubExpr where S: fmt::Debug + Clone, A: fmt::Debug + Clone, diff --git a/dhall/src/typecheck.rs b/dhall/src/typecheck.rs index a0782f8..babfad0 100644 --- a/dhall/src/typecheck.rs +++ b/dhall/src/typecheck.rs @@ -11,8 +11,11 @@ use self::TypeMessage::*; impl Resolved { pub fn typecheck(self) -> Result> { - let typ = crate::typecheck::type_of_(self.0.clone())?; - Ok(typ) + type_of_(self.0.clone()) + } + /// Pretends this expression has been typechecked. Use with care. + pub fn skip_typecheck(self) -> Typed { + Typed(self.0, UNTYPE) } } impl Typed { @@ -63,7 +66,7 @@ impl Normalized { } impl Type { #[inline(always)] - fn as_normalized(&self) -> Result<&Normalized, TypeError> { + pub fn as_normalized(&self) -> Result<&Normalized, TypeError> { use TypeInternal::*; match &self.0 { Expr(e) => Ok(e), diff --git a/dhall/tests/common/mod.rs b/dhall/tests/common/mod.rs index fc5aa5b..5f16d2c 100644 --- a/dhall/tests/common/mod.rs +++ b/dhall/tests/common/mod.rs @@ -44,20 +44,21 @@ pub enum Feature { TypeInferenceFailure, } +// Deprecated fn read_dhall_file<'i>(file_path: &str) -> Result, ImportError> { - load_dhall_file(&PathBuf::from(file_path), true) + dhall::load_dhall_file(&PathBuf::from(file_path), true) } fn load_from_file_str<'i>( file_path: &str, -) -> Result { - Parsed::load_from_file(&PathBuf::from(file_path)) +) -> Result { + dhall::expr::Parsed::load_from_file(&PathBuf::from(file_path)) } fn load_from_binary_file_str<'i>( file_path: &str, -) -> Result { - Parsed::load_from_binary_file(&PathBuf::from(file_path)) +) -> Result { + dhall::expr::Parsed::load_from_binary_file(&PathBuf::from(file_path)) } pub fn run_test(base_path: &str, feature: Feature) { @@ -88,7 +89,8 @@ pub fn run_test(base_path: &str, feature: Feature) { assert_eq_pretty!(expr, expected); // Round-trip pretty-printer - let expr = Parsed::load_from_str(&expr.to_string()).unwrap(); + let expr = + dhall::expr::Parsed::load_from_str(&expr.to_string()).unwrap(); assert_eq!(expr, expected); } ParserFailure => { @@ -102,15 +104,29 @@ pub fn run_test(base_path: &str, feature: Feature) { Normalization => { let expr_file_path = base_path.clone() + "A.dhall"; let expected_file_path = base_path + "B.dhall"; - let expr = rc(read_dhall_file(&expr_file_path).unwrap()); - let expected = rc(read_dhall_file(&expected_file_path).unwrap()); + let expr = load_from_file_str(&expr_file_path) + .unwrap() + .resolve() + .unwrap() + .skip_typecheck() + .normalize(); + let expected = load_from_file_str(&expected_file_path) + .unwrap() + .resolve() + .unwrap() + .skip_typecheck() + .normalize(); - assert_eq_display!(normalize(expr), normalize(expected)); + assert_eq_display!(expr, expected); } TypecheckFailure => { let file_path = base_path + ".dhall"; - let expr = rc(read_dhall_file(&file_path).unwrap()); - typecheck::type_of(expr).unwrap_err(); + load_from_file_str(&file_path) + .unwrap() + .skip_resolve() + .unwrap() + .typecheck() + .unwrap_err(); } TypecheckSuccess => { // Many tests stack overflow in debug mode @@ -131,15 +147,30 @@ pub fn run_test(base_path: &str, feature: Feature) { } TypeInferenceFailure => { let file_path = base_path + ".dhall"; - let expr = rc(read_dhall_file(&file_path).unwrap()); - typecheck::type_of(expr).unwrap_err(); + load_from_file_str(&file_path) + .unwrap() + .skip_resolve() + .unwrap() + .typecheck() + .unwrap_err(); } TypeInferenceSuccess => { let expr_file_path = base_path.clone() + "A.dhall"; let expected_file_path = base_path + "B.dhall"; - let expr = rc(read_dhall_file(&expr_file_path).unwrap()); - let expected = rc(read_dhall_file(&expected_file_path).unwrap()); - assert_eq_display!(typecheck::type_of(expr).unwrap(), expected); + let expr = load_from_file_str(&expr_file_path) + .unwrap() + .skip_resolve() + .unwrap() + .typecheck() + .unwrap(); + let ty = expr.get_type().as_normalized().unwrap(); + let expected = load_from_file_str(&expected_file_path) + .unwrap() + .skip_resolve() + .unwrap() + .skip_typecheck() + .skip_normalize(); + assert_eq_display!(ty, &expected); } } } -- cgit v1.3.1