diff options
Diffstat (limited to '')
-rw-r--r-- | Cargo.lock | 33 | ||||
-rw-r--r-- | Cargo.toml | 13 | ||||
-rw-r--r-- | dhall/.gitignore (renamed from dhall_generated_parser/.gitignore) | 0 | ||||
-rw-r--r-- | dhall/Cargo.toml | 16 | ||||
-rw-r--r-- | dhall/build.rs | 98 | ||||
l--------- | dhall/src/dhall.abnf (renamed from dhall_generated_parser/src/dhall.abnf) | 0 | ||||
-rw-r--r-- | dhall/src/dhall.pest.visibility (renamed from dhall_generated_parser/src/dhall.pest.visibility) | 0 | ||||
-rw-r--r-- | dhall/src/lib.rs | 5 | ||||
-rw-r--r-- | dhall/src/semantics/core/context.rs (renamed from dhall/src/core/context.rs) | 11 | ||||
-rw-r--r-- | dhall/src/semantics/core/mod.rs (renamed from dhall/src/core/mod.rs) | 0 | ||||
-rw-r--r-- | dhall/src/semantics/core/value.rs (renamed from dhall/src/core/value.rs) | 17 | ||||
-rw-r--r-- | dhall/src/semantics/core/valuef.rs (renamed from dhall/src/core/valuef.rs) | 14 | ||||
-rw-r--r-- | dhall/src/semantics/core/var.rs (renamed from dhall/src/core/var.rs) | 10 | ||||
-rw-r--r-- | dhall/src/semantics/error/mod.rs (renamed from dhall/src/error/mod.rs) | 11 | ||||
-rw-r--r-- | dhall/src/semantics/mod.rs | 3 | ||||
-rw-r--r-- | dhall/src/semantics/phase/mod.rs (renamed from dhall/src/phase/mod.rs) | 18 | ||||
-rw-r--r-- | dhall/src/semantics/phase/normalize.rs (renamed from dhall/src/phase/normalize.rs) | 22 | ||||
-rw-r--r-- | dhall/src/semantics/phase/parse.rs (renamed from dhall/src/phase/parse.rs) | 14 | ||||
-rw-r--r-- | dhall/src/semantics/phase/resolve.rs (renamed from dhall/src/phase/resolve.rs) | 13 | ||||
-rw-r--r-- | dhall/src/semantics/phase/typecheck.rs (renamed from dhall/src/phase/typecheck.rs) | 53 | ||||
-rw-r--r-- | dhall/src/syntax/binary/decode.rs (renamed from dhall/src/phase/binary.rs) | 329 | ||||
-rw-r--r-- | dhall/src/syntax/binary/encode.rs | 319 | ||||
-rw-r--r-- | dhall/src/syntax/binary/mod.rs | 4 | ||||
-rw-r--r-- | dhall/src/syntax/core/context.rs (renamed from dhall_syntax/src/core/context.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/core/expr.rs (renamed from dhall_syntax/src/core/expr.rs) | 8 | ||||
-rw-r--r-- | dhall/src/syntax/core/import.rs (renamed from dhall_syntax/src/core/import.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/core/label.rs (renamed from dhall_syntax/src/core/label.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/core/map.rs (renamed from dhall_syntax/src/core/map.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/core/mod.rs (renamed from dhall_syntax/src/core/mod.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/core/span.rs (renamed from dhall_syntax/src/core/span.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/core/text.rs (renamed from dhall_syntax/src/core/text.rs) | 0 | ||||
-rw-r--r-- | dhall/src/syntax/core/visitor.rs (renamed from dhall_syntax/src/core/visitor.rs) | 6 | ||||
-rw-r--r-- | dhall/src/syntax/mod.rs | 15 | ||||
-rw-r--r-- | dhall/src/syntax/text/mod.rs | 2 | ||||
-rw-r--r-- | dhall/src/syntax/text/parser.rs (renamed from dhall_syntax/src/parser.rs) | 180 | ||||
-rw-r--r-- | dhall/src/syntax/text/printer.rs (renamed from dhall_syntax/src/printer.rs) | 14 | ||||
-rw-r--r-- | dhall/src/tests.rs | 4 | ||||
-rw-r--r-- | dhall_generated_parser/Cargo.toml | 18 | ||||
-rw-r--r-- | dhall_generated_parser/build.rs | 90 | ||||
-rw-r--r-- | dhall_generated_parser/src/lib.rs | 22 | ||||
-rw-r--r-- | dhall_syntax/Cargo.toml | 21 | ||||
-rw-r--r-- | dhall_syntax/src/lib.rs | 22 | ||||
-rw-r--r-- | serde_dhall/Cargo.toml | 1 | ||||
-rw-r--r-- | serde_dhall/src/lib.rs | 8 | ||||
-rw-r--r-- | serde_dhall/src/serde.rs | 4 | ||||
-rw-r--r-- | serde_dhall/src/static_type.rs | 2 |
46 files changed, 658 insertions, 762 deletions
@@ -73,10 +73,16 @@ dependencies = [ name = "dhall" version = "0.1.0" dependencies = [ + "abnf_to_pest 0.1.1", "bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dhall_syntax 0.1.0", + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "improved_slice_patterns 2.0.0", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_consume 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_cbor 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -86,15 +92,6 @@ dependencies = [ ] [[package]] -name = "dhall_generated_parser" -version = "0.1.0" -dependencies = [ - "abnf_to_pest 0.1.1", - "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "dhall_proc_macros" version = "0.1.0" dependencies = [ @@ -105,21 +102,6 @@ dependencies = [ ] [[package]] -name = "dhall_syntax" -version = "0.1.0" -dependencies = [ - "dhall_generated_parser 0.1.0", - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "pest_consume 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "difference" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -376,7 +358,6 @@ version = "0.1.0" dependencies = [ "dhall 0.1.0", "dhall_proc_macros 0.1.0", - "dhall_syntax 0.1.0", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4,20 +4,7 @@ cargo-features = ["profile-overrides"] members = [ "abnf_to_pest", "dhall", - "dhall_generated_parser", - "dhall_syntax", "dhall_proc_macros", "improved_slice_patterns", "serde_dhall" ] - -# # Parser is super slow when not optimized -# [profile.dev.overrides.dhall_parser] -# opt-level = 3 -# [profile.dev.overrides.dhall_syntax] -# opt-level = 3 -# [profile.dev.overrides.dhall] -# opt-level = 3 -# [profile.dev] -# opt-level = 3 - diff --git a/dhall_generated_parser/.gitignore b/dhall/.gitignore index 8a0bac6..8a0bac6 100644 --- a/dhall_generated_parser/.gitignore +++ b/dhall/.gitignore diff --git a/dhall/Cargo.toml b/dhall/Cargo.toml index 16c1c78..962b466 100644 --- a/dhall/Cargo.toml +++ b/dhall/Cargo.toml @@ -8,17 +8,25 @@ build = "build.rs" [dependencies] bytecount = "0.5.1" +either = "1.5.2" +improved_slice_patterns = { version = "2.0.0", path = "../improved_slice_patterns" } itertools = "0.8.0" -take_mut = "0.2.2" -term-painter = "0.2.3" +hex = "0.3.2" +lazy_static = "1.4.0" +percent-encoding = "2.1.0" +pest = "2.1" +# pest_consume = { path = "../../pest_consume/pest_consume" } +pest_consume = "1.0" serde = { version = "1.0" } serde_cbor = "0.9.0" -improved_slice_patterns = { version = "2.0.0", path = "../improved_slice_patterns" } -dhall_syntax = { path = "../dhall_syntax" } +take_mut = "0.2.2" +term-painter = "0.2.3" [dev-dependencies] pretty_assertions = "0.6.1" [build-dependencies] walkdir = "2" +abnf_to_pest = { version = "0.1.1", path = "../abnf_to_pest" } + diff --git a/dhall/build.rs b/dhall/build.rs index a0106de..50f423e 100644 --- a/dhall/build.rs +++ b/dhall/build.rs @@ -1,10 +1,12 @@ use std::env; use std::ffi::OsString; use std::fs::File; -use std::io::Write; +use std::io::{BufRead, BufReader, Read, Write}; use std::path::{Path, PathBuf}; use walkdir::WalkDir; +use abnf_to_pest::render_rules_to_pest; + #[derive(Debug, Clone, Copy)] enum FileType { Text, @@ -100,7 +102,7 @@ fn make_test_module( Ok(()) } -fn main() -> std::io::Result<()> { +fn generate_tests() -> std::io::Result<()> { // Tries to detect when the submodule gets updated. // To force regeneration of the test list, just `touch dhall-lang/.git` println!("cargo:rerun-if-changed=../dhall-lang/.git"); @@ -404,3 +406,95 @@ fn main() -> std::io::Result<()> { Ok(()) } + +fn convert_abnf_to_pest() -> std::io::Result<()> { + let abnf_path = "src/dhall.abnf"; + let visibility_path = "src/dhall.pest.visibility"; + let pest_path = "src/dhall.pest"; + println!("cargo:rerun-if-changed={}", abnf_path); + println!("cargo:rerun-if-changed={}", visibility_path); + + let mut file = File::open(abnf_path)?; + let mut data = Vec::new(); + file.read_to_end(&mut data)?; + data.push('\n' as u8); + + let mut rules = abnf_to_pest::parse_abnf(&data)?; + for line in BufReader::new(File::open(visibility_path)?).lines() { + let line = line?; + if line.len() >= 2 && &line[0..2] == "# " { + rules.get_mut(&line[2..]).map(|x| x.silent = true); + } + } + + let mut file = File::create(pest_path)?; + writeln!(&mut file, "// AUTO-GENERATED FILE. See build.rs.")?; + + // TODO: this is a cheat; properly support RFC3986 URLs instead + rules.remove("url_path"); + writeln!(&mut file, "url_path = _{{ path }}")?; + + rules.remove("simple_label"); + writeln!( + &mut file, + "simple_label = {{ + keyword ~ simple_label_next_char+ + | !keyword ~ simple_label_first_char ~ simple_label_next_char* + }}" + )?; + + rules.remove("nonreserved_label"); + writeln!( + &mut file, + "nonreserved_label = _{{ + !(builtin ~ !simple_label_next_char) ~ label + }}" + )?; + + // Setup grammar for precedence climbing + rules.remove("operator_expression"); + writeln!(&mut file, r##" + import_alt = {{ "?" ~ whsp1 }} + bool_or = {{ "||" }} + natural_plus = {{ "+" ~ whsp1 }} + text_append = {{ "++" }} + list_append = {{ "#" }} + bool_and = {{ "&&" }} + natural_times = {{ "*" }} + bool_eq = {{ "==" }} + bool_ne = {{ "!=" }} + + operator = _{{ + equivalent | + bool_ne | + bool_eq | + natural_times | + combine_types | + prefer | + combine | + bool_and | + list_append | + text_append | + natural_plus | + bool_or | + import_alt + }} + operator_expression = {{ application_expression ~ (whsp ~ operator ~ whsp ~ application_expression)* }} + "##)?; + + writeln!( + &mut file, + "final_expression = ${{ SOI ~ complete_expression ~ EOI }}" + )?; + + writeln!(&mut file)?; + writeln!(&mut file, "{}", render_rules_to_pest(rules).pretty(80))?; + + Ok(()) +} + +fn main() -> std::io::Result<()> { + convert_abnf_to_pest()?; + generate_tests()?; + Ok(()) +} diff --git a/dhall_generated_parser/src/dhall.abnf b/dhall/src/dhall.abnf index ce13b8e..ce13b8e 120000 --- a/dhall_generated_parser/src/dhall.abnf +++ b/dhall/src/dhall.abnf diff --git a/dhall_generated_parser/src/dhall.pest.visibility b/dhall/src/dhall.pest.visibility index 17c1edc..17c1edc 100644 --- a/dhall_generated_parser/src/dhall.pest.visibility +++ b/dhall/src/dhall.pest.visibility diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index ed4435a..0991375 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -12,6 +12,5 @@ mod tests; -pub mod core; -pub mod error; -pub mod phase; +pub mod semantics; +pub mod syntax; diff --git a/dhall/src/core/context.rs b/dhall/src/semantics/core/context.rs index 2bf39c5..d150e56 100644 --- a/dhall/src/core/context.rs +++ b/dhall/src/semantics/core/context.rs @@ -1,12 +1,11 @@ use std::collections::HashMap; use std::rc::Rc; -use dhall_syntax::{Label, V}; - -use crate::core::value::Value; -use crate::core::valuef::ValueF; -use crate::core::var::{AlphaVar, Shift, Subst}; -use crate::error::TypeError; +use crate::semantics::core::value::Value; +use crate::semantics::core::valuef::ValueF; +use crate::semantics::core::var::{AlphaVar, Shift, Subst}; +use crate::semantics::error::TypeError; +use crate::syntax::{Label, V}; #[derive(Debug, Clone)] enum CtxItem { diff --git a/dhall/src/core/mod.rs b/dhall/src/semantics/core/mod.rs index 08213f7..08213f7 100644 --- a/dhall/src/core/mod.rs +++ b/dhall/src/semantics/core/mod.rs diff --git a/dhall/src/core/value.rs b/dhall/src/semantics/core/value.rs index d4f5131..6e6739f 100644 --- a/dhall/src/core/value.rs +++ b/dhall/src/semantics/core/value.rs @@ -1,15 +1,14 @@ use std::cell::{Ref, RefCell, RefMut}; use std::rc::Rc; -use dhall_syntax::{Builtin, Const, Span}; - -use crate::core::context::TypecheckContext; -use crate::core::valuef::ValueF; -use crate::core::var::{AlphaVar, Shift, Subst}; -use crate::error::{TypeError, TypeMessage}; -use crate::phase::normalize::{apply_any, normalize_whnf}; -use crate::phase::typecheck::{builtin_to_value, const_to_value}; -use crate::phase::{NormalizedExpr, Typed}; +use crate::semantics::core::context::TypecheckContext; +use crate::semantics::core::valuef::ValueF; +use crate::semantics::core::var::{AlphaVar, Shift, Subst}; +use crate::semantics::error::{TypeError, TypeMessage}; +use crate::semantics::phase::normalize::{apply_any, normalize_whnf}; +use crate::semantics::phase::typecheck::{builtin_to_value, const_to_value}; +use crate::semantics::phase::{NormalizedExpr, Typed}; +use crate::syntax::{Builtin, Const, Span}; #[derive(Debug, Clone, Copy)] pub(crate) enum Form { diff --git a/dhall/src/core/valuef.rs b/dhall/src/semantics/core/valuef.rs index e5d0807..73c715a 100644 --- a/dhall/src/core/valuef.rs +++ b/dhall/src/semantics/core/valuef.rs @@ -1,15 +1,15 @@ use std::collections::HashMap; -use dhall_syntax::{ +use crate::semantics::core::value::{ToExprOptions, Value}; +use crate::semantics::core::var::{AlphaLabel, AlphaVar, Shift, Subst}; +use crate::semantics::phase::typecheck::rc; +use crate::semantics::phase::{Normalized, NormalizedExpr}; +use crate::syntax; +use crate::syntax::{ Builtin, Const, ExprF, Integer, InterpolatedTextContents, Label, NaiveDouble, Natural, }; -use crate::core::value::{ToExprOptions, Value}; -use crate::core::var::{AlphaLabel, AlphaVar, Shift, Subst}; -use crate::phase::typecheck::rc; -use crate::phase::{Normalized, NormalizedExpr}; - /// A semantic value. Subexpressions are Values, which are partially evaluated expressions that are /// normalized on-demand. /// If you compare for equality two `ValueF`s in WHNF, then equality will be up to @@ -117,7 +117,7 @@ impl ValueF { .collect(), )), ValueF::Equivalence(x, y) => rc(ExprF::BinOp( - dhall_syntax::BinOp::Equivalence, + syntax::BinOp::Equivalence, x.to_expr(opts), y.to_expr(opts), )), diff --git a/dhall/src/core/var.rs b/dhall/src/semantics/core/var.rs index 3795f10..184a372 100644 --- a/dhall/src/core/var.rs +++ b/dhall/src/semantics/core/var.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use dhall_syntax::{Label, V}; +use crate::syntax::{ExprF, InterpolatedTextContents, Label, V}; /// Stores a pair of variables: a normal one and one /// that corresponds to the alpha-normalized version of the first one. @@ -190,7 +190,7 @@ impl<T: Shift> Shift for std::cell::RefCell<T> { } } -impl<T: Shift, E: Clone> Shift for dhall_syntax::ExprF<T, E> { +impl<T: Shift, E: Clone> Shift for ExprF<T, E> { fn shift(&self, delta: isize, var: &AlphaVar) -> Option<Self> { Some(self.traverse_ref_with_special_handling_of_binders( |v| Ok(v.shift(delta, var)?), @@ -222,7 +222,7 @@ where } } -impl<T: Shift> Shift for dhall_syntax::InterpolatedTextContents<T> { +impl<T: Shift> Shift for InterpolatedTextContents<T> { fn shift(&self, delta: isize, var: &AlphaVar) -> Option<Self> { Some(self.traverse_ref(|x| Ok(x.shift(delta, var)?))?) } @@ -262,7 +262,7 @@ impl<S, T: Subst<S>> Subst<S> for std::cell::RefCell<T> { } } -impl<S: Shift, T: Subst<S>, E: Clone> Subst<S> for dhall_syntax::ExprF<T, E> { +impl<S: Shift, T: Subst<S>, E: Clone> Subst<S> for ExprF<T, E> { fn subst_shift(&self, var: &AlphaVar, val: &S) -> Self { self.map_ref_with_special_handling_of_binders( |v| v.subst_shift(var, val), @@ -277,7 +277,7 @@ impl<S, T: Subst<S>> Subst<S> for Vec<T> { } } -impl<S, T: Subst<S>> Subst<S> for dhall_syntax::InterpolatedTextContents<T> { +impl<S, T: Subst<S>> Subst<S> for InterpolatedTextContents<T> { fn subst_shift(&self, var: &AlphaVar, val: &S) -> Self { self.map_ref(|x| x.subst_shift(var, val)) } diff --git a/dhall/src/error/mod.rs b/dhall/src/semantics/error/mod.rs index e4baea0..1288c12 100644 --- a/dhall/src/error/mod.rs +++ b/dhall/src/semantics/error/mod.rs @@ -1,11 +1,10 @@ use std::io::Error as IOError; -use dhall_syntax::{BinOp, Import, Label, ParseError, Span}; - -use crate::core::context::TypecheckContext; -use crate::core::value::Value; -use crate::phase::resolve::ImportStack; -use crate::phase::NormalizedExpr; +use crate::semantics::core::context::TypecheckContext; +use crate::semantics::core::value::Value; +use crate::semantics::phase::resolve::ImportStack; +use crate::semantics::phase::NormalizedExpr; +use crate::syntax::{BinOp, Import, Label, ParseError, Span}; pub type Result<T> = std::result::Result<T, Error>; diff --git a/dhall/src/semantics/mod.rs b/dhall/src/semantics/mod.rs new file mode 100644 index 0000000..9d2e462 --- /dev/null +++ b/dhall/src/semantics/mod.rs @@ -0,0 +1,3 @@ +pub mod core; +pub mod error; +pub mod phase; diff --git a/dhall/src/phase/mod.rs b/dhall/src/semantics/phase/mod.rs index 337ce3d..752c257 100644 --- a/dhall/src/phase/mod.rs +++ b/dhall/src/semantics/phase/mod.rs @@ -1,16 +1,14 @@ use std::fmt::Display; use std::path::Path; -use dhall_syntax::{Builtin, Const, Expr}; - -use crate::core::value::{ToExprOptions, Value}; -use crate::core::valuef::ValueF; -use crate::core::var::{AlphaVar, Shift, Subst}; -use crate::error::{EncodeError, Error, ImportError, TypeError}; - +use crate::semantics::core::value::{ToExprOptions, Value}; +use crate::semantics::core::valuef::ValueF; +use crate::semantics::core::var::{AlphaVar, Shift, Subst}; +use crate::semantics::error::{EncodeError, Error, ImportError, TypeError}; +use crate::syntax::binary; +use crate::syntax::{Builtin, Const, Expr}; use resolve::ImportRoot; -pub(crate) mod binary; pub(crate) mod normalize; pub(crate) mod parse; pub(crate) mod resolve; @@ -62,7 +60,7 @@ impl Parsed { } pub fn encode(&self) -> Result<Vec<u8>, EncodeError> { - crate::phase::binary::encode(&self.0) + binary::encode(&self.0) } } @@ -172,7 +170,7 @@ impl Typed { impl Normalized { pub fn encode(&self) -> Result<Vec<u8>, EncodeError> { - crate::phase::binary::encode(&self.to_expr()) + binary::encode(&self.to_expr()) } pub(crate) fn to_expr(&self) -> NormalizedExpr { diff --git a/dhall/src/phase/normalize.rs b/dhall/src/semantics/phase/normalize.rs index b712027..81c3ce1 100644 --- a/dhall/src/phase/normalize.rs +++ b/dhall/src/semantics/phase/normalize.rs @@ -1,21 +1,21 @@ use std::collections::HashMap; -use dhall_syntax::Const::Type; -use dhall_syntax::{ +use crate::semantics::core::value::Value; +use crate::semantics::core::valuef::ValueF; +use crate::semantics::core::var::{AlphaLabel, AlphaVar, Shift, Subst}; +use crate::semantics::phase::Normalized; +use crate::syntax; +use crate::syntax::Const::Type; +use crate::syntax::{ BinOp, Builtin, ExprF, InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, }; -use crate::core::value::Value; -use crate::core::valuef::ValueF; -use crate::core::var::{AlphaLabel, Shift, Subst}; -use crate::phase::Normalized; - // Ad-hoc macro to help construct closures macro_rules! make_closure { (#$var:ident) => { $var.clone() }; (var($var:ident, $n:expr, $($ty:tt)*)) => {{ - let var = crate::core::var::AlphaVar::from_var_and_alpha( + let var = AlphaVar::from_var_and_alpha( Label::from(stringify!($var)).into(), $n ); @@ -47,7 +47,7 @@ macro_rules! make_closure { }}; (1 + $($rest:tt)*) => { ValueF::PartialExpr(ExprF::BinOp( - dhall_syntax::BinOp::NaturalPlus, + syntax::BinOp::NaturalPlus, make_closure!($($rest)*), Value::from_valuef_and_type( ValueF::NaturalLit(1), @@ -62,7 +62,7 @@ macro_rules! make_closure { let tail = make_closure!($($tail)*); let list_type = tail.get_type_not_sort(); ValueF::PartialExpr(ExprF::BinOp( - dhall_syntax::BinOp::ListAppend, + syntax::BinOp::ListAppend, ValueF::NEListLit(vec![head]) .into_value_with_type(list_type.clone()), tail, @@ -76,7 +76,7 @@ pub(crate) fn apply_builtin( args: Vec<Value>, ty: &Value, ) -> ValueF { - use dhall_syntax::Builtin::*; + use syntax::Builtin::*; use ValueF::*; // Small helper enum diff --git a/dhall/src/phase/parse.rs b/dhall/src/semantics/phase/parse.rs index 540ceea..4c8ad7b 100644 --- a/dhall/src/phase/parse.rs +++ b/dhall/src/semantics/phase/parse.rs @@ -2,11 +2,11 @@ use std::fs::File; use std::io::Read; use std::path::Path; -use dhall_syntax::parse_expr; - -use crate::error::Error; -use crate::phase::resolve::ImportRoot; -use crate::phase::Parsed; +use crate::semantics::error::Error; +use crate::semantics::phase::resolve::ImportRoot; +use crate::semantics::phase::Parsed; +use crate::syntax::binary; +use crate::syntax::parse_expr; pub(crate) fn parse_file(f: &Path) -> Result<Parsed, Error> { let mut buffer = String::new(); @@ -23,7 +23,7 @@ pub(crate) fn parse_str(s: &str) -> Result<Parsed, Error> { } pub(crate) fn parse_binary(data: &[u8]) -> Result<Parsed, Error> { - let expr = crate::phase::binary::decode(data)?; + let expr = binary::decode(data)?; let root = ImportRoot::LocalDir(std::env::current_dir()?); Ok(Parsed(expr, root)) } @@ -31,7 +31,7 @@ pub(crate) fn parse_binary(data: &[u8]) -> Result<Parsed, Error> { pub(crate) fn parse_binary_file(f: &Path) -> Result<Parsed, Error> { let mut buffer = Vec::new(); File::open(f)?.read_to_end(&mut buffer)?; - let expr = crate::phase::binary::decode(&buffer)?; + let expr = binary::decode(&buffer)?; let root = ImportRoot::LocalDir(f.parent().unwrap().to_owned()); Ok(Parsed(expr, root)) } diff --git a/dhall/src/phase/resolve.rs b/dhall/src/semantics/phase/resolve.rs index c302bfa..86dc7ae 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/semantics/phase/resolve.rs @@ -1,11 +1,12 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use crate::error::{Error, ImportError}; -use crate::phase::{Normalized, NormalizedExpr, Parsed, Resolved}; -use dhall_syntax::{FilePath, ImportLocation, URL}; +use crate::semantics::error::{Error, ImportError}; +use crate::semantics::phase::{Normalized, NormalizedExpr, Parsed, Resolved}; +use crate::syntax; +use crate::syntax::{FilePath, ImportLocation, URL}; -type Import = dhall_syntax::Import<NormalizedExpr>; +type Import = syntax::Import<NormalizedExpr>; /// A root from which to resolve relative imports. #[derive(Debug, Clone, PartialEq, Eq)] @@ -24,8 +25,8 @@ fn resolve_import( import_stack: &ImportStack, ) -> Result<Normalized, ImportError> { use self::ImportRoot::*; - use dhall_syntax::FilePrefix::*; - use dhall_syntax::ImportLocation::*; + use syntax::FilePrefix::*; + use syntax::ImportLocation::*; let cwd = match root { LocalDir(cwd) => cwd, }; diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/semantics/phase/typecheck.rs index ef8340d..59380a3 100644 --- a/dhall/src/phase/typecheck.rs +++ b/dhall/src/semantics/phase/typecheck.rs @@ -1,24 +1,25 @@ use std::cmp::max; use std::collections::HashMap; -use dhall_syntax::{ +use crate::semantics::core::context::TypecheckContext; +use crate::semantics::core::value::Value; +use crate::semantics::core::valuef::ValueF; +use crate::semantics::core::var::{Shift, Subst}; +use crate::semantics::error::{TypeError, TypeMessage}; +use crate::semantics::phase::normalize::merge_maps; +use crate::semantics::phase::Normalized; +use crate::syntax; +use crate::syntax::{ Builtin, Const, Expr, ExprF, InterpolatedTextContents, Label, RawExpr, Span, }; -use crate::core::context::TypecheckContext; -use crate::core::value::Value; -use crate::core::valuef::ValueF; -use crate::core::var::{Shift, Subst}; -use crate::error::{TypeError, TypeMessage}; -use crate::phase::Normalized; - fn tck_pi_type( ctx: &TypecheckContext, x: Label, tx: Value, te: Value, ) -> Result<Value, TypeError> { - use crate::error::TypeMessage::*; + use TypeMessage::*; let ctx2 = ctx.insert_type(&x, tx.clone()); let ka = match tx.get_type()?.as_const() { @@ -48,8 +49,8 @@ fn tck_record_type( ctx: &TypecheckContext, kts: impl IntoIterator<Item = Result<(Label, Value), TypeError>>, ) -> Result<Value, TypeError> { - use crate::error::TypeMessage::*; use std::collections::hash_map::Entry; + use TypeMessage::*; let mut new_kts = HashMap::new(); // An empty record type has type Type let mut k = Const::Type; @@ -83,8 +84,8 @@ fn tck_union_type<Iter>( where Iter: IntoIterator<Item = Result<(Label, Option<Value>), TypeError>>, { - use crate::error::TypeMessage::*; use std::collections::hash_map::Entry; + use TypeMessage::*; let mut new_kts = HashMap::new(); // Check that all types are the same const let mut k = None; @@ -155,7 +156,7 @@ macro_rules! make_type { (Double) => { ExprF::Builtin(Builtin::Double) }; (Text) => { ExprF::Builtin(Builtin::Text) }; ($var:ident) => { - ExprF::Var(dhall_syntax::V(stringify!($var).into(), 0)) + ExprF::Var(syntax::V(stringify!($var).into(), 0)) }; (Optional $ty:ident) => { ExprF::App( @@ -170,7 +171,7 @@ macro_rules! make_type { ) }; ({ $($label:ident : $ty:ident),* }) => {{ - let mut kts = dhall_syntax::map::DupTreeMap::new(); + let mut kts = syntax::map::DupTreeMap::new(); $( kts.insert( Label::from(stringify!($label)), @@ -203,7 +204,7 @@ macro_rules! make_type { } fn type_of_builtin<E>(b: Builtin) -> Expr<E> { - use dhall_syntax::Builtin::*; + use syntax::Builtin::*; rc(match b { Bool | Natural | Integer | Double | Text => make_type!(Type), List | Optional => make_type!( @@ -303,7 +304,7 @@ fn type_with( ctx: &TypecheckContext, e: Expr<Normalized>, ) -> Result<Value, TypeError> { - use dhall_syntax::ExprF::{Annot, Embed, Lam, Let, Pi, Var}; + use syntax::ExprF::{Annot, Embed, Lam, Let, Pi, Var}; let span = e.span(); Ok(match e.as_ref() { @@ -361,11 +362,11 @@ fn type_last_layer( e: ExprF<Value, Normalized>, span: Span, ) -> Result<Value, TypeError> { - use crate::error::TypeMessage::*; - use dhall_syntax::BinOp::*; - use dhall_syntax::Builtin::*; - use dhall_syntax::Const::Type; - use dhall_syntax::ExprF::*; + use syntax::BinOp::*; + use syntax::Builtin::*; + use syntax::Const::Type; + use syntax::ExprF::*; + use TypeMessage::*; let mkerr = |msg: TypeMessage| Err(TypeError::new(ctx, msg)); /// Intermediary return type @@ -434,7 +435,7 @@ fn type_last_layer( } EmptyListLit(t) => { match &*t.as_whnf() { - ValueF::AppliedBuiltin(dhall_syntax::Builtin::List, args) + ValueF::AppliedBuiltin(syntax::Builtin::List, args) if args.len() == 1 => {} _ => return mkerr(InvalidListType(t.clone())), } @@ -457,7 +458,7 @@ fn type_last_layer( return mkerr(InvalidListType(t)); } - RetTypeOnly(Value::from_builtin(dhall_syntax::Builtin::List).app(t)) + RetTypeOnly(Value::from_builtin(syntax::Builtin::List).app(t)) } SomeLit(x) => { let t = x.get_type()?; @@ -465,9 +466,7 @@ fn type_last_layer( return mkerr(InvalidOptionalType(t)); } - RetTypeOnly( - Value::from_builtin(dhall_syntax::Builtin::Optional).app(t), - ) + RetTypeOnly(Value::from_builtin(syntax::Builtin::Optional).app(t)) } RecordType(kts) => RetWhole(tck_record_type( ctx, @@ -548,8 +547,6 @@ fn type_last_layer( RetTypeOnly(text_type) } BinOp(RightBiasedRecordMerge, l, r) => { - use crate::phase::normalize::merge_maps; - let l_type = l.get_type()?; let r_type = r.get_type()?; @@ -589,8 +586,6 @@ fn type_last_layer( Span::Artificial, )?), BinOp(RecursiveRecordTypeMerge, l, r) => { - use crate::phase::normalize::merge_maps; - // Extract the LHS record type let borrow_l = l.as_whnf(); let kts_x = match &*borrow_l { diff --git a/dhall/src/phase/binary.rs b/dhall/src/syntax/binary/decode.rs index 0639120..46c9921 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/syntax/binary/decode.rs @@ -1,18 +1,15 @@ use itertools::Itertools; use serde_cbor::value::value as cbor; use std::iter::FromIterator; -use std::vec; -use dhall_syntax::map::DupTreeMap; -use dhall_syntax::{ - Expr, ExprF, FilePath, FilePrefix, Hash, Import, ImportLocation, - ImportMode, Integer, InterpolatedText, Label, Natural, RawExpr, Scheme, - Span, URL, V, +use crate::semantics::error::DecodeError; +use crate::semantics::phase::DecodedExpr; +use crate::syntax; +use crate::syntax::{ + Expr, ExprF, FilePath, FilePrefix, Hash, ImportLocation, ImportMode, + Integer, InterpolatedText, Label, Natural, RawExpr, Scheme, Span, URL, V, }; -use crate::error::{DecodeError, EncodeError}; -use crate::phase::DecodedExpr; - pub(crate) fn decode(data: &[u8]) -> Result<DecodedExpr, DecodeError> { match serde_cbor::de::from_slice(data) { Ok(v) => cbor_value_to_dhall(&v), @@ -20,19 +17,14 @@ pub(crate) fn decode(data: &[u8]) -> Result<DecodedExpr, DecodeError> { } } -pub(crate) fn encode<E>(expr: &Expr<E>) -> Result<Vec<u8>, EncodeError> { - serde_cbor::ser::to_vec(&Serialize::Expr(expr)) - .map_err(|e| EncodeError::CBORError(e)) -} - // Should probably rename this -pub fn rc<E>(x: RawExpr<E>) -> Expr<E> { +fn rc<E>(x: RawExpr<E>) -> Expr<E> { Expr::new(x, Span::Decoded) } fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> { use cbor::Value::*; - use dhall_syntax::{BinOp, Builtin, Const}; + use syntax::{BinOp, Builtin, Const}; use ExprF::*; Ok(rc(match data { String(s) => match Builtin::parse(s) { @@ -350,7 +342,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<DecodedExpr, DecodeError> { "import/type".to_owned(), ))?, }; - Import(dhall_syntax::Import { + Import(syntax::Import { mode, hash, location, @@ -443,306 +435,3 @@ where }) .collect::<Result<_, _>>() } - -enum Serialize<'a, E> { - Expr(&'a Expr<E>), - CBOR(cbor::Value), - RecordMap(&'a DupTreeMap<Label, Expr<E>>), - UnionMap(&'a DupTreeMap<Label, Option<Expr<E>>>), -} - -macro_rules! count { - (@replace_with $_t:tt $sub:expr) => { $sub }; - ($($tts:tt)*) => {0usize $(+ count!(@replace_with $tts 1usize))*}; -} - -macro_rules! ser_seq { - ($ser:expr; $($elt:expr),* $(,)?) => {{ - use serde::ser::SerializeSeq; - let count = count!($($elt)*); - let mut ser_seq = $ser.serialize_seq(Some(count))?; - $( - ser_seq.serialize_element(&$elt)?; - )* - ser_seq.end() - }}; -} - -fn serialize_subexpr<S, E>(ser: S, e: &Expr<E>) -> Result<S::Ok, S::Error> -where - S: serde::ser::Serializer, -{ - use cbor::Value::{String, I64, U64}; - use dhall_syntax::Builtin; - use dhall_syntax::ExprF::*; - use std::iter::once; - - use self::Serialize::{RecordMap, UnionMap}; - fn expr<E>(x: &Expr<E>) -> self::Serialize<'_, E> { - self::Serialize::Expr(x) - } - let cbor = - |v: cbor::Value| -> self::Serialize<'_, E> { self::Serialize::CBOR(v) }; - let tag = |x: u64| cbor(U64(x)); - let null = || cbor(cbor::Value::Null); - let label = |l: &Label| cbor(cbor::Value::String(l.into())); - - match e.as_ref() { - Const(c) => ser.serialize_str(&c.to_string()), - Builtin(b) => ser.serialize_str(&b.to_string()), - BoolLit(b) => ser.serialize_bool(*b), - NaturalLit(n) => ser_seq!(ser; tag(15), U64(*n as u64)), - IntegerLit(n) => ser_seq!(ser; tag(16), I64(*n as i64)), - DoubleLit(n) => { - let n: f64 = (*n).into(); - ser.serialize_f64(n) - } - BoolIf(x, y, z) => ser_seq!(ser; tag(14), expr(x), expr(y), expr(z)), - Var(V(l, n)) if l == &"_".into() => ser.serialize_u64(*n as u64), - Var(V(l, n)) => ser_seq!(ser; label(l), U64(*n as u64)), - Lam(l, x, y) if l == &"_".into() => { - ser_seq!(ser; tag(1), expr(x), expr(y)) - } - Lam(l, x, y) => ser_seq!(ser; tag(1), label(l), expr(x), expr(y)), - Pi(l, x, y) if l == &"_".into() => { - ser_seq!(ser; tag(2), expr(x), expr(y)) - } - Pi(l, x, y) => ser_seq!(ser; tag(2), label(l), expr(x), expr(y)), - Let(_, _, _, _) => { - let (bound_e, bindings) = collect_nested_lets(e); - let count = 1 + 3 * bindings.len() + 1; - - use serde::ser::SerializeSeq; - let mut ser_seq = ser.serialize_seq(Some(count))?; - ser_seq.serialize_element(&tag(25))?; - for (l, t, v) in bindings { - ser_seq.serialize_element(&label(l))?; - match t { - Some(t) => ser_seq.serialize_element(&expr(t))?, - None => ser_seq.serialize_element(&null())?, - } - ser_seq.serialize_element(&expr(v))?; - } - ser_seq.serialize_element(&expr(bound_e))?; - ser_seq.end() - } - App(_, _) => { - let (f, args) = collect_nested_applications(e); - ser.collect_seq( - once(tag(0)) - .chain(once(expr(f))) - .chain(args.into_iter().rev().map(expr)), - ) - } - Annot(x, y) => ser_seq!(ser; tag(26), expr(x), expr(y)), - Assert(x) => ser_seq!(ser; tag(19), expr(x)), - SomeLit(x) => ser_seq!(ser; tag(5), null(), expr(x)), - EmptyListLit(x) => match x.as_ref() { - App(f, a) => match f.as_ref() { - ExprF::Builtin(Builtin::List) => ser_seq!(ser; tag(4), expr(a)), - _ => ser_seq!(ser; tag(28), expr(x)), - }, - _ => ser_seq!(ser; tag(28), expr(x)), - }, - NEListLit(xs) => ser.collect_seq( - once(tag(4)).chain(once(null())).chain(xs.iter().map(expr)), - ), - TextLit(xs) => { - use dhall_syntax::InterpolatedTextContents::{Expr, Text}; - ser.collect_seq(once(tag(18)).chain(xs.iter().map(|x| match x { - Expr(x) => expr(x), - Text(x) => cbor(String(x.clone())), - }))) - } - RecordType(map) => ser_seq!(ser; tag(7), RecordMap(map)), - RecordLit(map) => ser_seq!(ser; tag(8), RecordMap(map)), - UnionType(map) => ser_seq!(ser; tag(11), UnionMap(map)), - Field(x, l) => ser_seq!(ser; tag(9), expr(x), label(l)), - BinOp(op, x, y) => { - use dhall_syntax::BinOp::*; - let op = match op { - BoolOr => 0, - BoolAnd => 1, - BoolEQ => 2, - BoolNE => 3, - NaturalPlus => 4, - NaturalTimes => 5, - TextAppend => 6, - ListAppend => 7, - RecursiveRecordMerge => 8, - RightBiasedRecordMerge => 9, - RecursiveRecordTypeMerge => 10, - ImportAlt => 11, - Equivalence => 12, - }; - ser_seq!(ser; tag(3), U64(op), expr(x), expr(y)) - } - Merge(x, y, None) => ser_seq!(ser; tag(6), expr(x), expr(y)), - Merge(x, y, Some(z)) => { - ser_seq!(ser; tag(6), expr(x), expr(y), expr(z)) - } - ToMap(x, None) => ser_seq!(ser; tag(27), expr(x)), - ToMap(x, Some(y)) => ser_seq!(ser; tag(27), expr(x), expr(y)), - Projection(x, ls) => ser.collect_seq( - once(tag(10)) - .chain(once(expr(x))) - .chain(ls.iter().map(label)), - ), - ProjectionByExpr(x, y) => { - ser_seq!(ser; tag(10), expr(x), vec![expr(y)]) - } - Import(import) => serialize_import(ser, import), - Embed(_) => unimplemented!( - "An expression with resolved imports cannot be binary-encoded" - ), - } -} - -fn serialize_import<S, E>( - ser: S, - import: &Import<Expr<E>>, -) -> Result<S::Ok, S::Error> -where - S: serde::ser::Serializer, -{ - use cbor::Value::{Bytes, Null, U64}; - use serde::ser::SerializeSeq; - - let count = 4 + match &import.location { - ImportLocation::Remote(url) => 3 + url.path.file_path.len(), - ImportLocation::Local(_, path) => path.file_path.len(), - ImportLocation::Env(_) => 1, - ImportLocation::Missing => 0, - }; - let mut ser_seq = ser.serialize_seq(Some(count))?; - - ser_seq.serialize_element(&U64(24))?; - - let hash = match &import.hash { - None => Null, - Some(Hash::SHA256(h)) => { - let mut bytes = vec![18, 32]; - bytes.extend_from_slice(h); - Bytes(bytes) - } - }; - ser_seq.serialize_element(&hash)?; - - let mode = match import.mode { - ImportMode::Code => 0, - ImportMode::RawText => 1, - ImportMode::Location => 2, - }; - ser_seq.serialize_element(&U64(mode))?; - - let scheme = match &import.location { - ImportLocation::Remote(url) => match url.scheme { - Scheme::HTTP => 0, - Scheme::HTTPS => 1, - }, - ImportLocation::Local(prefix, _) => match prefix { - FilePrefix::Absolute => 2, - FilePrefix::Here => 3, - FilePrefix::Parent => 4, - FilePrefix::Home => 5, - }, - ImportLocation::Env(_) => 6, - ImportLocation::Missing => 7, - }; - ser_seq.serialize_element(&U64(scheme))?; - - match &import.location { - ImportLocation::Remote(url) => { - match &url.headers { - None => ser_seq.serialize_element(&Null)?, - Some(e) => { - ser_seq.serialize_element(&self::Serialize::Expr(e))? - } - }; - ser_seq.serialize_element(&url.authority)?; - for p in url.path.file_path.iter() { - ser_seq.serialize_element(&p)?; - } - match &url.query { - None => ser_seq.serialize_element(&Null)?, - Some(x) => ser_seq.serialize_element(x)?, - }; - } - ImportLocation::Local(_, path) => { - for p in path.file_path.iter() { - ser_seq.serialize_element(&p)?; - } - } - ImportLocation::Env(env) => { - ser_seq.serialize_element(env)?; - } - ImportLocation::Missing => {} - } - - ser_seq.end() -} - -impl<'a, E> serde::ser::Serialize for Serialize<'a, E> { - fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error> - where - S: serde::ser::Serializer, - { - match self { - Serialize::Expr(e) => serialize_subexpr(ser, e), - Serialize::CBOR(v) => v.serialize(ser), - Serialize::RecordMap(map) => { - ser.collect_map(map.iter().map(|(k, v)| { - (cbor::Value::String(k.into()), Serialize::Expr(v)) - })) - } - Serialize::UnionMap(map) => { - ser.collect_map(map.iter().map(|(k, v)| { - let v = match v { - Some(x) => Serialize::Expr(x), - None => Serialize::CBOR(cbor::Value::Null), - }; - (cbor::Value::String(k.into()), v) - })) - } - } - } -} - -fn collect_nested_applications<'a, E>( - e: &'a Expr<E>, -) -> (&'a Expr<E>, Vec<&'a Expr<E>>) { - fn go<'a, E>(e: &'a Expr<E>, vec: &mut Vec<&'a Expr<E>>) -> &'a Expr<E> { - match e.as_ref() { - ExprF::App(f, a) => { - vec.push(a); - go(f, vec) - } - _ => e, - } - } - let mut vec = vec![]; - let e = go(e, &mut vec); - (e, vec) -} - -type LetBinding<'a, E> = (&'a Label, &'a Option<Expr<E>>, &'a Expr<E>); - -fn collect_nested_lets<'a, E>( - e: &'a Expr<E>, -) -> (&'a Expr<E>, Vec<LetBinding<'a, E>>) { - fn go<'a, E>( - e: &'a Expr<E>, - vec: &mut Vec<LetBinding<'a, E>>, - ) -> &'a Expr<E> { - match e.as_ref() { - ExprF::Let(l, t, v, e) => { - vec.push((l, t, v)); - go(e, vec) - } - _ => e, - } - } - let mut vec = vec![]; - let e = go(e, &mut vec); - (e, vec) -} diff --git a/dhall/src/syntax/binary/encode.rs b/dhall/src/syntax/binary/encode.rs new file mode 100644 index 0000000..8e13efd --- /dev/null +++ b/dhall/src/syntax/binary/encode.rs @@ -0,0 +1,319 @@ +use serde_cbor::value::value as cbor; +use std::vec; + +use crate::semantics::error::EncodeError; +use crate::syntax; +use crate::syntax::map::DupTreeMap; +use crate::syntax::{ + Expr, ExprF, FilePrefix, Hash, Import, ImportLocation, ImportMode, Label, + Scheme, V, +}; + +/// Warning: will fail if `expr` contains an `Embed` node. +pub(crate) fn encode<E>(expr: &Expr<E>) -> Result<Vec<u8>, EncodeError> { + serde_cbor::ser::to_vec(&Serialize::Expr(expr)) + .map_err(|e| EncodeError::CBORError(e)) +} + +enum Serialize<'a, E> { + Expr(&'a Expr<E>), + CBOR(cbor::Value), + RecordMap(&'a DupTreeMap<Label, Expr<E>>), + UnionMap(&'a DupTreeMap<Label, Option<Expr<E>>>), +} + +macro_rules! count { + (@replace_with $_t:tt $sub:expr) => { $sub }; + ($($tts:tt)*) => {0usize $(+ count!(@replace_with $tts 1usize))*}; +} + +macro_rules! ser_seq { + ($ser:expr; $($elt:expr),* $(,)?) => {{ + use serde::ser::SerializeSeq; + let count = count!($($elt)*); + let mut ser_seq = $ser.serialize_seq(Some(count))?; + $( + ser_seq.serialize_element(&$elt)?; + )* + ser_seq.end() + }}; +} + +fn serialize_subexpr<S, E>(ser: S, e: &Expr<E>) -> Result<S::Ok, S::Error> +where + S: serde::ser::Serializer, +{ + use cbor::Value::{String, I64, U64}; + use std::iter::once; + use syntax::Builtin; + use syntax::ExprF::*; + + use self::Serialize::{RecordMap, UnionMap}; + fn expr<E>(x: &Expr<E>) -> self::Serialize<'_, E> { + self::Serialize::Expr(x) + } + let cbor = + |v: cbor::Value| -> self::Serialize<'_, E> { self::Serialize::CBOR(v) }; + let tag = |x: u64| cbor(U64(x)); + let null = || cbor(cbor::Value::Null); + let label = |l: &Label| cbor(cbor::Value::String(l.into())); + + match e.as_ref() { + Const(c) => ser.serialize_str(&c.to_string()), + Builtin(b) => ser.serialize_str(&b.to_string()), + BoolLit(b) => ser.serialize_bool(*b), + NaturalLit(n) => ser_seq!(ser; tag(15), U64(*n as u64)), + IntegerLit(n) => ser_seq!(ser; tag(16), I64(*n as i64)), + DoubleLit(n) => { + let n: f64 = (*n).into(); + ser.serialize_f64(n) + } + BoolIf(x, y, z) => ser_seq!(ser; tag(14), expr(x), expr(y), expr(z)), + Var(V(l, n)) if l == &"_".into() => ser.serialize_u64(*n as u64), + Var(V(l, n)) => ser_seq!(ser; label(l), U64(*n as u64)), + Lam(l, x, y) if l == &"_".into() => { + ser_seq!(ser; tag(1), expr(x), expr(y)) + } + Lam(l, x, y) => ser_seq!(ser; tag(1), label(l), expr(x), expr(y)), + Pi(l, x, y) if l == &"_".into() => { + ser_seq!(ser; tag(2), expr(x), expr(y)) + } + Pi(l, x, y) => ser_seq!(ser; tag(2), label(l), expr(x), expr(y)), + Let(_, _, _, _) => { + let (bound_e, bindings) = collect_nested_lets(e); + let count = 1 + 3 * bindings.len() + 1; + + use serde::ser::SerializeSeq; + let mut ser_seq = ser.serialize_seq(Some(count))?; + ser_seq.serialize_element(&tag(25))?; + for (l, t, v) in bindings { + ser_seq.serialize_element(&label(l))?; + match t { + Some(t) => ser_seq.serialize_element(&expr(t))?, + None => ser_seq.serialize_element(&null())?, + } + ser_seq.serialize_element(&expr(v))?; + } + ser_seq.serialize_element(&expr(bound_e))?; + ser_seq.end() + } + App(_, _) => { + let (f, args) = collect_nested_applications(e); + ser.collect_seq( + once(tag(0)) + .chain(once(expr(f))) + .chain(args.into_iter().rev().map(expr)), + ) + } + Annot(x, y) => ser_seq!(ser; tag(26), expr(x), expr(y)), + Assert(x) => ser_seq!(ser; tag(19), expr(x)), + SomeLit(x) => ser_seq!(ser; tag(5), null(), expr(x)), + EmptyListLit(x) => match x.as_ref() { + App(f, a) => match f.as_ref() { + ExprF::Builtin(Builtin::List) => ser_seq!(ser; tag(4), expr(a)), + _ => ser_seq!(ser; tag(28), expr(x)), + }, + _ => ser_seq!(ser; tag(28), expr(x)), + }, + NEListLit(xs) => ser.collect_seq( + once(tag(4)).chain(once(null())).chain(xs.iter().map(expr)), + ), + TextLit(xs) => { + use syntax::InterpolatedTextContents::{Expr, Text}; + ser.collect_seq(once(tag(18)).chain(xs.iter().map(|x| match x { + Expr(x) => expr(x), + Text(x) => cbor(String(x.clone())), + }))) + } + RecordType(map) => ser_seq!(ser; tag(7), RecordMap(map)), + RecordLit(map) => ser_seq!(ser; tag(8), RecordMap(map)), + UnionType(map) => ser_seq!(ser; tag(11), UnionMap(map)), + Field(x, l) => ser_seq!(ser; tag(9), expr(x), label(l)), + BinOp(op, x, y) => { + use syntax::BinOp::*; + let op = match op { + BoolOr => 0, + BoolAnd => 1, + BoolEQ => 2, + BoolNE => 3, + NaturalPlus => 4, + NaturalTimes => 5, + TextAppend => 6, + ListAppend => 7, + RecursiveRecordMerge => 8, + RightBiasedRecordMerge => 9, + RecursiveRecordTypeMerge => 10, + ImportAlt => 11, + Equivalence => 12, + }; + ser_seq!(ser; tag(3), U64(op), expr(x), expr(y)) + } + Merge(x, y, None) => ser_seq!(ser; tag(6), expr(x), expr(y)), + Merge(x, y, Some(z)) => { + ser_seq!(ser; tag(6), expr(x), expr(y), expr(z)) + } + ToMap(x, None) => ser_seq!(ser; tag(27), expr(x)), + ToMap(x, Some(y)) => ser_seq!(ser; tag(27), expr(x), expr(y)), + Projection(x, ls) => ser.collect_seq( + once(tag(10)) + .chain(once(expr(x))) + .chain(ls.iter().map(label)), + ), + ProjectionByExpr(x, y) => { + ser_seq!(ser; tag(10), expr(x), vec![expr(y)]) + } + Import(import) => serialize_import(ser, import), + Embed(_) => unimplemented!( + "An expression with resolved imports cannot be binary-encoded" + ), + } +} + +fn serialize_import<S, E>( + ser: S, + import: &Import<Expr<E>>, +) -> Result<S::Ok, S::Error> +where + S: serde::ser::Serializer, +{ + use cbor::Value::{Bytes, Null, U64}; + use serde::ser::SerializeSeq; + + let count = 4 + match &import.location { + ImportLocation::Remote(url) => 3 + url.path.file_path.len(), + ImportLocation::Local(_, path) => path.file_path.len(), + ImportLocation::Env(_) => 1, + ImportLocation::Missing => 0, + }; + let mut ser_seq = ser.serialize_seq(Some(count))?; + + ser_seq.serialize_element(&U64(24))?; + + let hash = match &import.hash { + None => Null, + Some(Hash::SHA256(h)) => { + let mut bytes = vec![18, 32]; + bytes.extend_from_slice(h); + Bytes(bytes) + } + }; + ser_seq.serialize_element(&hash)?; + + let mode = match import.mode { + ImportMode::Code => 0, + ImportMode::RawText => 1, + ImportMode::Location => 2, + }; + ser_seq.serialize_element(&U64(mode))?; + + let scheme = match &import.location { + ImportLocation::Remote(url) => match url.scheme { + Scheme::HTTP => 0, + Scheme::HTTPS => 1, + }, + ImportLocation::Local(prefix, _) => match prefix { + FilePrefix::Absolute => 2, + FilePrefix::Here => 3, + FilePrefix::Parent => 4, + FilePrefix::Home => 5, + }, + ImportLocation::Env(_) => 6, + ImportLocation::Missing => 7, + }; + ser_seq.serialize_element(&U64(scheme))?; + + match &import.location { + ImportLocation::Remote(url) => { + match &url.headers { + None => ser_seq.serialize_element(&Null)?, + Some(e) => { + ser_seq.serialize_element(&self::Serialize::Expr(e))? + } + }; + ser_seq.serialize_element(&url.authority)?; + for p in url.path.file_path.iter() { + ser_seq.serialize_element(&p)?; + } + match &url.query { + None => ser_seq.serialize_element(&Null)?, + Some(x) => ser_seq.serialize_element(x)?, + }; + } + ImportLocation::Local(_, path) => { + for p in path.file_path.iter() { + ser_seq.serialize_element(&p)?; + } + } + ImportLocation::Env(env) => { + ser_seq.serialize_element(env)?; + } + ImportLocation::Missing => {} + } + + ser_seq.end() +} + +impl<'a, E> serde::ser::Serialize for Serialize<'a, E> { + fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error> + where + S: serde::ser::Serializer, + { + match self { + Serialize::Expr(e) => serialize_subexpr(ser, e), + Serialize::CBOR(v) => v.serialize(ser), + Serialize::RecordMap(map) => { + ser.collect_map(map.iter().map(|(k, v)| { + (cbor::Value::String(k.into()), Serialize::Expr(v)) + })) + } + Serialize::UnionMap(map) => { + ser.collect_map(map.iter().map(|(k, v)| { + let v = match v { + Some(x) => Serialize::Expr(x), + None => Serialize::CBOR(cbor::Value::Null), + }; + (cbor::Value::String(k.into()), v) + })) + } + } + } +} + +fn collect_nested_applications<'a, E>( + e: &'a Expr<E>, +) -> (&'a Expr<E>, Vec<&'a Expr<E>>) { + fn go<'a, E>(e: &'a Expr<E>, vec: &mut Vec<&'a Expr<E>>) -> &'a Expr<E> { + match e.as_ref() { + ExprF::App(f, a) => { + vec.push(a); + go(f, vec) + } + _ => e, + } + } + let mut vec = vec![]; + let e = go(e, &mut vec); + (e, vec) +} + +type LetBinding<'a, E> = (&'a Label, &'a Option<Expr<E>>, &'a Expr<E>); + +fn collect_nested_lets<'a, E>( + e: &'a Expr<E>, +) -> (&'a Expr<E>, Vec<LetBinding<'a, E>>) { + fn go<'a, E>( + e: &'a Expr<E>, + vec: &mut Vec<LetBinding<'a, E>>, + ) -> &'a Expr<E> { + match e.as_ref() { + ExprF::Let(l, t, v, e) => { + vec.push((l, t, v)); + go(e, vec) + } + _ => e, + } + } + let mut vec = vec![]; + let e = go(e, &mut vec); + (e, vec) +} diff --git a/dhall/src/syntax/binary/mod.rs b/dhall/src/syntax/binary/mod.rs new file mode 100644 index 0000000..7ed1f6e --- /dev/null +++ b/dhall/src/syntax/binary/mod.rs @@ -0,0 +1,4 @@ +mod decode; +mod encode; +pub(crate) use decode::decode; +pub(crate) use encode::encode; diff --git a/dhall_syntax/src/core/context.rs b/dhall/src/syntax/core/context.rs index 6844baa..6844baa 100644 --- a/dhall_syntax/src/core/context.rs +++ b/dhall/src/syntax/core/context.rs diff --git a/dhall_syntax/src/core/expr.rs b/dhall/src/syntax/core/expr.rs index 131f97e..5b9f401 100644 --- a/dhall_syntax/src/core/expr.rs +++ b/dhall/src/syntax/core/expr.rs @@ -1,6 +1,6 @@ -use crate::map::{DupTreeMap, DupTreeSet}; -use crate::visitor::{self, ExprFMutVisitor, ExprFVisitor}; -use crate::*; +use crate::syntax::map::{DupTreeMap, DupTreeSet}; +use crate::syntax::visitor::{self, ExprFMutVisitor, ExprFVisitor}; +use crate::syntax::*; pub type Integer = isize; pub type Natural = usize; @@ -351,7 +351,7 @@ impl<E> Expr<E> { } /// Add an isize to an usize -/// Panics on over/underflow +/// Returns `None` on over/underflow fn add_ui(u: usize, i: isize) -> Option<usize> { Some(if i < 0 { u.checked_sub(i.checked_neg()? as usize)? diff --git a/dhall_syntax/src/core/import.rs b/dhall/src/syntax/core/import.rs index da3e99b..da3e99b 100644 --- a/dhall_syntax/src/core/import.rs +++ b/dhall/src/syntax/core/import.rs diff --git a/dhall_syntax/src/core/label.rs b/dhall/src/syntax/core/label.rs index 43c3f53..43c3f53 100644 --- a/dhall_syntax/src/core/label.rs +++ b/dhall/src/syntax/core/label.rs diff --git a/dhall_syntax/src/core/map.rs b/dhall/src/syntax/core/map.rs index c4c6126..c4c6126 100644 --- a/dhall_syntax/src/core/map.rs +++ b/dhall/src/syntax/core/map.rs diff --git a/dhall_syntax/src/core/mod.rs b/dhall/src/syntax/core/mod.rs index 66bf229..66bf229 100644 --- a/dhall_syntax/src/core/mod.rs +++ b/dhall/src/syntax/core/mod.rs diff --git a/dhall_syntax/src/core/span.rs b/dhall/src/syntax/core/span.rs index f9c7008..f9c7008 100644 --- a/dhall_syntax/src/core/span.rs +++ b/dhall/src/syntax/core/span.rs diff --git a/dhall_syntax/src/core/text.rs b/dhall/src/syntax/core/text.rs index fb390ee..fb390ee 100644 --- a/dhall_syntax/src/core/text.rs +++ b/dhall/src/syntax/core/text.rs diff --git a/dhall_syntax/src/core/visitor.rs b/dhall/src/syntax/core/visitor.rs index 143e556..b76d037 100644 --- a/dhall_syntax/src/core/visitor.rs +++ b/dhall/src/syntax/core/visitor.rs @@ -1,4 +1,4 @@ -use crate::*; +use crate::syntax::*; use std::iter::FromIterator; /// A visitor trait that can be used to traverse `ExprF`s. We need this pattern so that Rust lets @@ -111,7 +111,7 @@ where .collect() } - use crate::ExprF::*; + use crate::syntax::ExprF::*; Ok(match input { Var(v) => Var(v.clone()), Lam(l, t, e) => { @@ -225,7 +225,7 @@ where Ok(()) } - use crate::ExprF::*; + use crate::syntax::ExprF::*; match input { Var(_) | Const(_) | Builtin(_) | BoolLit(_) | NaturalLit(_) | IntegerLit(_) | DoubleLit(_) => {} diff --git a/dhall/src/syntax/mod.rs b/dhall/src/syntax/mod.rs new file mode 100644 index 0000000..a82e827 --- /dev/null +++ b/dhall/src/syntax/mod.rs @@ -0,0 +1,15 @@ +#![allow( + clippy::many_single_char_names, + clippy::should_implement_trait, + clippy::new_without_default, + clippy::type_complexity +)] + +mod core; +pub use crate::syntax::core::context; +pub use crate::syntax::core::visitor; +pub use crate::syntax::core::*; +pub use crate::syntax::text::parser::*; +pub use crate::syntax::text::printer::*; +pub mod binary; +pub mod text; diff --git a/dhall/src/syntax/text/mod.rs b/dhall/src/syntax/text/mod.rs new file mode 100644 index 0000000..c868288 --- /dev/null +++ b/dhall/src/syntax/text/mod.rs @@ -0,0 +1,2 @@ +pub mod parser; +pub mod printer; diff --git a/dhall_syntax/src/parser.rs b/dhall/src/syntax/text/parser.rs index f5d161f..f6b6577 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -3,36 +3,42 @@ use pest::prec_climber as pcl; use pest::prec_climber::PrecClimber; use std::rc::Rc; -use dgp::Rule; -use dhall_generated_parser as dgp; use pest_consume::{match_nodes, Parser}; -use crate::map::{DupTreeMap, DupTreeSet}; -use crate::ExprF::*; -use crate::*; +use crate::semantics::phase::Normalized; +use crate::syntax; +use crate::syntax::core; +use crate::syntax::map::{DupTreeMap, DupTreeSet}; +use crate::syntax::ExprF::*; +use crate::syntax::{ + FilePath, FilePrefix, Hash, ImportLocation, ImportMode, InterpolatedText, + InterpolatedTextContents, Label, NaiveDouble, RawExpr, Scheme, Span, URL, + V, +}; // This file consumes the parse tree generated by pest and turns it into // our own AST. All those custom macros should eventually moved into // their own crate because they are quite general and useful. For now they // are here and hopefully you can figure out how they work. -type ParsedText<E> = InterpolatedText<Expr<E>>; -type ParsedTextContents<E> = InterpolatedTextContents<Expr<E>>; +type Expr = syntax::Expr<Normalized>; +type ParsedText = InterpolatedText<Expr>; +type ParsedTextContents = InterpolatedTextContents<Expr>; type ParseInput<'input> = pest_consume::Node<'input, Rule, Rc<str>>; pub type ParseError = pest::error::Error<Rule>; pub type ParseResult<T> = Result<T, ParseError>; #[derive(Debug)] -enum Selector<E> { +enum Selector { Field(Label), Projection(DupTreeSet<Label>), - ProjectionByExpr(Expr<E>), + ProjectionByExpr(Expr), } -impl crate::Builtin { +impl crate::syntax::Builtin { pub fn parse(s: &str) -> Option<Self> { - use crate::Builtin::*; + use crate::syntax::Builtin::*; match s { "Bool" => Some(Bool), "Natural" => Some(Natural), @@ -71,16 +77,16 @@ impl crate::Builtin { fn input_to_span(input: ParseInput) -> Span { Span::make(input.user_data().clone(), input.as_pair().as_span()) } -fn spanned<E>(input: ParseInput, x: RawExpr<E>) -> Expr<E> { +fn spanned(input: ParseInput, x: RawExpr<Normalized>) -> Expr { Expr::new(x, input_to_span(input)) } -fn spanned_union<E>(span1: Span, span2: Span, x: RawExpr<E>) -> Expr<E> { +fn spanned_union(span1: Span, span2: Span, x: RawExpr<Normalized>) -> Expr { Expr::new(x, span1.union(&span2)) } // Trim the shared indent off of a vec of lines, as defined by the Dhall semantics of multiline // literals. -fn trim_indent<E: Clone>(lines: &mut Vec<ParsedText<E>>) { +fn trim_indent(lines: &mut Vec<ParsedText>) { let is_indent = |c: char| c == ' ' || c == '\t'; // There is at least one line so this is safe @@ -147,9 +153,11 @@ lazy_static::lazy_static! { }; } +#[derive(Parser)] +#[grammar = "dhall.pest"] struct DhallParser; -#[pest_consume::parser(parser = dgp::DhallParser, rule = dgp::Rule)] +#[pest_consume::parser(parser = DhallParser, rule = Rule)] impl DhallParser { fn EOI(_input: ParseInput) -> ParseResult<()> { Ok(()) @@ -164,9 +172,7 @@ impl DhallParser { Ok(Label::from(input.as_str())) } - fn double_quote_literal<E: Clone>( - input: ParseInput, - ) -> ParseResult<ParsedText<E>> { + fn double_quote_literal(input: ParseInput) -> ParseResult<ParsedText> { Ok(match_nodes!(input.into_children(); [double_quote_chunk(chunks)..] => { chunks.collect() @@ -174,9 +180,9 @@ impl DhallParser { )) } - fn double_quote_chunk<E: Clone>( + fn double_quote_chunk( input: ParseInput, - ) -> ParseResult<ParsedTextContents<E>> { + ) -> ParseResult<ParsedTextContents> { Ok(match_nodes!(input.into_children(); [expression(e)] => { InterpolatedTextContents::Expr(e) @@ -261,18 +267,16 @@ impl DhallParser { Ok(input.as_str().to_owned()) } - fn single_quote_literal<E: Clone>( - input: ParseInput, - ) -> ParseResult<ParsedText<E>> { + fn single_quote_literal(input: ParseInput) -> ParseResult<ParsedText> { Ok(match_nodes!(input.into_children(); [single_quote_continue(lines)] => { - let newline: ParsedText<E> = "\n".to_string().into(); + let newline: ParsedText = "\n".to_string().into(); // Reverse lines and chars in each line - let mut lines: Vec<ParsedText<E>> = lines + let mut lines: Vec<ParsedText> = lines .into_iter() .rev() - .map(|l| l.into_iter().rev().collect::<ParsedText<E>>()) + .map(|l| l.into_iter().rev().collect::<ParsedText>()) .collect(); trim_indent(&mut lines); @@ -281,7 +285,7 @@ impl DhallParser { .into_iter() .intersperse(newline) .flat_map(InterpolatedText::into_iter) - .collect::<ParsedText<E>>() + .collect::<ParsedText>() } )) } @@ -298,9 +302,9 @@ impl DhallParser { } // Returns a vec of lines in reversed order, where each line is also in reversed order. - fn single_quote_continue<E: Clone>( + fn single_quote_continue( input: ParseInput, - ) -> ParseResult<Vec<Vec<ParsedTextContents<E>>>> { + ) -> ParseResult<Vec<Vec<ParsedTextContents>>> { Ok(match_nodes!(input.into_children(); [expression(e), single_quote_continue(lines)] => { let c = InterpolatedTextContents::Expr(e); @@ -326,16 +330,16 @@ impl DhallParser { } #[alias(expression)] - fn builtin<E: Clone>(input: ParseInput) -> ParseResult<Expr<E>> { + fn builtin(input: ParseInput) -> ParseResult<Expr> { let s = input.as_str(); - let e = match crate::Builtin::parse(s) { + let e = match crate::syntax::Builtin::parse(s) { Some(b) => Builtin(b), None => match s { "True" => BoolLit(true), "False" => BoolLit(false), - "Type" => Const(crate::Const::Type), - "Kind" => Const(crate::Const::Kind), - "Sort" => Const(crate::Const::Sort), + "Type" => Const(crate::syntax::Const::Type), + "Kind" => Const(crate::syntax::Const::Kind), + "Sort" => Const(crate::syntax::Const::Sort), _ => { Err(input.error(format!("Unrecognized builtin: '{}'", s)))? } @@ -387,7 +391,7 @@ impl DhallParser { } #[alias(expression, shortcut = true)] - fn identifier<E: Clone>(input: ParseInput) -> ParseResult<Expr<E>> { + fn identifier(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.children(); [variable(v)] => spanned(input, Var(v)), [expression(e)] => e, @@ -441,9 +445,7 @@ impl DhallParser { } #[alias(import_type)] - fn local<E: Clone>( - input: ParseInput, - ) -> ParseResult<ImportLocation<Expr<E>>> { + fn local(input: ParseInput) -> ParseResult<ImportLocation<Expr>> { Ok(match_nodes!(input.into_children(); [local_path((prefix, p))] => ImportLocation::Local(prefix, p), )) @@ -482,7 +484,7 @@ impl DhallParser { }) } - fn http_raw<E: Clone>(input: ParseInput) -> ParseResult<URL<Expr<E>>> { + fn http_raw(input: ParseInput) -> ParseResult<URL<Expr>> { Ok(match_nodes!(input.into_children(); [scheme(sch), authority(auth), path(p)] => URL { scheme: sch, @@ -510,9 +512,7 @@ impl DhallParser { } #[alias(import_type)] - fn http<E: Clone>( - input: ParseInput, - ) -> ParseResult<ImportLocation<Expr<E>>> { + fn http(input: ParseInput) -> ParseResult<ImportLocation<Expr>> { Ok(ImportLocation::Remote(match_nodes!(input.into_children(); [http_raw(url)] => url, [http_raw(url), expression(e)] => URL { headers: Some(e), ..url }, @@ -520,9 +520,7 @@ impl DhallParser { } #[alias(import_type)] - fn env<E: Clone>( - input: ParseInput, - ) -> ParseResult<ImportLocation<Expr<E>>> { + fn env(input: ParseInput) -> ParseResult<ImportLocation<Expr>> { Ok(match_nodes!(input.into_children(); [environment_variable(v)] => ImportLocation::Env(v), )) @@ -557,9 +555,7 @@ impl DhallParser { } #[alias(import_type)] - fn missing<E: Clone>( - _input: ParseInput, - ) -> ParseResult<ImportLocation<Expr<E>>> { + fn missing(_input: ParseInput) -> ParseResult<ImportLocation<Expr>> { Ok(ImportLocation::Missing) } @@ -573,10 +569,10 @@ impl DhallParser { Ok(Hash::SHA256(hex::decode(hash).unwrap())) } - fn import_hashed<E: Clone>( + fn import_hashed( input: ParseInput, - ) -> ParseResult<crate::Import<Expr<E>>> { - use crate::Import; + ) -> ParseResult<crate::syntax::Import<Expr>> { + use crate::syntax::Import; let mode = ImportMode::Code; Ok(match_nodes!(input.into_children(); [import_type(location)] => Import { mode, location, hash: None }, @@ -594,8 +590,8 @@ impl DhallParser { } #[alias(expression)] - fn import<E: Clone>(input: ParseInput) -> ParseResult<Expr<E>> { - use crate::Import; + fn import(input: ParseInput) -> ParseResult<Expr> { + use crate::syntax::Import; let import = match_nodes!(input.children(); [import_hashed(imp)] => { Import { mode: ImportMode::Code, ..imp } @@ -630,13 +626,13 @@ impl DhallParser { } #[alias(expression)] - fn empty_list_literal<E: Clone>(input: ParseInput) -> ParseResult<Expr<E>> { + fn empty_list_literal(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.children(); [expression(e)] => spanned(input, EmptyListLit(e)), )) } - fn expression<E: Clone>(input: ParseInput) -> ParseResult<Expr<E>> { + fn expression(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.children(); [lambda(()), label(l), expression(typ), arrow(()), expression(body)] => { @@ -681,9 +677,9 @@ impl DhallParser { )) } - fn let_binding<E: Clone>( + fn let_binding( input: ParseInput, - ) -> ParseResult<(Label, Option<Expr<E>>, Expr<E>, Span)> { + ) -> ParseResult<(Label, Option<Expr>, Expr, Span)> { Ok(match_nodes!(input.children(); [label(name), expression(annot), expression(expr)] => (name, Some(annot), expr, input_to_span(input)), @@ -694,12 +690,12 @@ impl DhallParser { #[alias(expression, shortcut = true)] #[prec_climb(expression, PRECCLIMBER)] - fn operator_expression<E: Clone>( - l: Expr<E>, + fn operator_expression( + l: Expr, op: ParseInput, - r: Expr<E>, - ) -> ParseResult<Expr<E>> { - use crate::BinOp::*; + r: Expr, + ) -> ParseResult<Expr> { + use crate::syntax::BinOp::*; use Rule::*; let op = match op.as_rule() { import_alt => ImportAlt, @@ -726,9 +722,7 @@ impl DhallParser { } #[alias(expression, shortcut = true)] - fn application_expression<E: Clone>( - input: ParseInput, - ) -> ParseResult<Expr<E>> { + fn application_expression(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.children(); [expression(e)] => e, [expression(first), expression(rest)..] => { @@ -747,9 +741,7 @@ impl DhallParser { } #[alias(expression, shortcut = true)] - fn first_application_expression<E: Clone>( - input: ParseInput, - ) -> ParseResult<Expr<E>> { + fn first_application_expression(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.children(); [Some_(()), expression(e)] => { spanned(input, SomeLit(e)) @@ -765,9 +757,7 @@ impl DhallParser { } #[alias(expression, shortcut = true)] - fn selector_expression<E: Clone>( - input: ParseInput, - ) -> ParseResult<Expr<E>> { + fn selector_expression(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.children(); [expression(e)] => e, [expression(first), selector(rest)..] => { @@ -789,9 +779,7 @@ impl DhallParser { )) } - fn selector<E: Clone>( - input: ParseInput, - ) -> ParseResult<(Selector<E>, Span)> { + fn selector(input: ParseInput) -> ParseResult<(Selector, Span)> { let stor = match_nodes!(input.children(); [label(l)] => Selector::Field(l), [labels(ls)] => Selector::Projection(ls), @@ -807,9 +795,7 @@ impl DhallParser { } #[alias(expression, shortcut = true)] - fn primitive_expression<E: Clone>( - input: ParseInput, - ) -> ParseResult<Expr<E>> { + fn primitive_expression(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.children(); [double_literal(n)] => spanned(input, DoubleLit(n)), [natural_literal(n)] => spanned(input, NaturalLit(n)), @@ -821,21 +807,19 @@ impl DhallParser { } #[alias(expression)] - fn empty_record_literal<E: Clone>( - input: ParseInput, - ) -> ParseResult<Expr<E>> { + fn empty_record_literal(input: ParseInput) -> ParseResult<Expr> { Ok(spanned(input, RecordLit(Default::default()))) } #[alias(expression)] - fn empty_record_type<E: Clone>(input: ParseInput) -> ParseResult<Expr<E>> { + fn empty_record_type(input: ParseInput) -> ParseResult<Expr> { Ok(spanned(input, RecordType(Default::default()))) } #[alias(expression)] - fn non_empty_record_type_or_literal<E: Clone>( + fn non_empty_record_type_or_literal( input: ParseInput, - ) -> ParseResult<Expr<E>> { + ) -> ParseResult<Expr> { let e = match_nodes!(input.children(); [label(first_label), non_empty_record_type(rest)] => { let (first_expr, mut map) = rest; @@ -851,9 +835,9 @@ impl DhallParser { Ok(spanned(input, e)) } - fn non_empty_record_type<E: Clone>( + fn non_empty_record_type( input: ParseInput, - ) -> ParseResult<(Expr<E>, DupTreeMap<Label, Expr<E>>)> { + ) -> ParseResult<(Expr, DupTreeMap<Label, Expr>)> { Ok(match_nodes!(input.into_children(); [expression(expr), record_type_entry(entries)..] => { (expr, entries.collect()) @@ -861,17 +845,15 @@ impl DhallParser { )) } - fn record_type_entry<E: Clone>( - input: ParseInput, - ) -> ParseResult<(Label, Expr<E>)> { + fn record_type_entry(input: ParseInput) -> ParseResult<(Label, Expr)> { Ok(match_nodes!(input.into_children(); [label(name), expression(expr)] => (name, expr) )) } - fn non_empty_record_literal<E: Clone>( + fn non_empty_record_literal( input: ParseInput, - ) -> ParseResult<(Expr<E>, DupTreeMap<Label, Expr<E>>)> { + ) -> ParseResult<(Expr, DupTreeMap<Label, Expr>)> { Ok(match_nodes!(input.into_children(); [expression(expr), record_literal_entry(entries)..] => { (expr, entries.collect()) @@ -879,16 +861,14 @@ impl DhallParser { )) } - fn record_literal_entry<E: Clone>( - input: ParseInput, - ) -> ParseResult<(Label, Expr<E>)> { + fn record_literal_entry(input: ParseInput) -> ParseResult<(Label, Expr)> { Ok(match_nodes!(input.into_children(); [label(name), expression(expr)] => (name, expr) )) } #[alias(expression)] - fn union_type<E: Clone>(input: ParseInput) -> ParseResult<Expr<E>> { + fn union_type(input: ParseInput) -> ParseResult<Expr> { let map = match_nodes!(input.children(); [empty_union_type(_)] => Default::default(), [union_type_entry(entries)..] => entries.collect(), @@ -900,9 +880,9 @@ impl DhallParser { Ok(()) } - fn union_type_entry<E: Clone>( + fn union_type_entry( input: ParseInput, - ) -> ParseResult<(Label, Option<Expr<E>>)> { + ) -> ParseResult<(Label, Option<Expr>)> { Ok(match_nodes!(input.children(); [label(name), expression(expr)] => (name, Some(expr)), [label(name)] => (name, None), @@ -910,9 +890,7 @@ impl DhallParser { } #[alias(expression)] - fn non_empty_list_literal<E: Clone>( - input: ParseInput, - ) -> ParseResult<Expr<E>> { + fn non_empty_list_literal(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.children(); [expression(items)..] => spanned( input, @@ -922,14 +900,14 @@ impl DhallParser { } #[alias(expression)] - fn final_expression<E: Clone>(input: ParseInput) -> ParseResult<Expr<E>> { + fn final_expression(input: ParseInput) -> ParseResult<Expr> { Ok(match_nodes!(input.into_children(); [expression(e), EOI(_)] => e )) } } -pub fn parse_expr<E: Clone>(input_str: &str) -> ParseResult<Expr<E>> { +pub fn parse_expr(input_str: &str) -> ParseResult<Expr> { let rc_input_str = input_str.to_string().into(); let inputs = DhallParser::parse_with_userdata( Rule::final_expression, diff --git a/dhall_syntax/src/printer.rs b/dhall/src/syntax/text/printer.rs index ce6ff97..8df456b 100644 --- a/dhall_syntax/src/printer.rs +++ b/dhall/src/syntax/text/printer.rs @@ -1,11 +1,11 @@ -use crate::*; +use crate::syntax::*; use itertools::Itertools; use std::fmt::{self, Display}; /// Generic instance that delegates to subexpressions impl<SE: Display + Clone, E: Display> Display for ExprF<SE, E> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::ExprF::*; + use crate::syntax::ExprF::*; match self { Lam(a, b, c) => { write!(f, "λ({} : {}) → {}", a, b, c)?; @@ -141,7 +141,7 @@ impl<A: Display + Clone> RawExpr<A> { f: &mut fmt::Formatter, phase: PrintPhase, ) -> Result<(), fmt::Error> { - use crate::ExprF::*; + use crate::syntax::ExprF::*; use PrintPhase::*; let needs_paren = match self { @@ -298,7 +298,7 @@ impl Display for Const { impl Display for BinOp { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::BinOp::*; + use crate::syntax::BinOp::*; f.write_str(match self { BoolOr => "||", TextAppend => "++", @@ -344,7 +344,7 @@ impl Display for Label { let is_reserved = match s.as_str() { "let" | "in" | "if" | "then" | "else" | "Type" | "Kind" | "Sort" | "True" | "False" => true, - _ => crate::Builtin::parse(&s).is_some(), + _ => crate::syntax::Builtin::parse(&s).is_some(), }; if !is_reserved && s.chars().all(|c| c.is_ascii_alphanumeric()) { write!(f, "{}", s) @@ -443,7 +443,7 @@ impl<SubExpr: Display> Display for Import<SubExpr> { impl Display for Builtin { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::Builtin::*; + use crate::syntax::Builtin::*; f.write_str(match *self { Bool => "Bool", Natural => "Natural", @@ -480,7 +480,7 @@ impl Display for Builtin { impl Display for Scheme { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use crate::Scheme::*; + use crate::syntax::Scheme::*; f.write_str(match *self { HTTP => "http", HTTPS => "https", diff --git a/dhall/src/tests.rs b/dhall/src/tests.rs index 1037ef9..9e5c744 100644 --- a/dhall/src/tests.rs +++ b/dhall/src/tests.rs @@ -47,8 +47,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::{Error, Result}; -use crate::phase::Parsed; +use crate::semantics::error::{Error, Result}; +use crate::semantics::phase::Parsed; #[allow(dead_code)] #[derive(Clone)] diff --git a/dhall_generated_parser/Cargo.toml b/dhall_generated_parser/Cargo.toml deleted file mode 100644 index b1f0d02..0000000 --- a/dhall_generated_parser/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "dhall_generated_parser" -version = "0.1.0" -authors = ["Nadrieril <nadrieril@users.noreply.github.com>"] -license = "BSD-2-Clause" -edition = "2018" -build = "build.rs" - -[lib] -test = false -doctest = false - -[build-dependencies] -abnf_to_pest = { version = "0.1.1", path = "../abnf_to_pest" } - -[dependencies] -pest = "2.1" -pest_derive = "2.1" diff --git a/dhall_generated_parser/build.rs b/dhall_generated_parser/build.rs deleted file mode 100644 index d846f92..0000000 --- a/dhall_generated_parser/build.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::fs::File; -use std::io::{BufRead, BufReader, Read, Write}; - -use abnf_to_pest::render_rules_to_pest; - -fn main() -> std::io::Result<()> { - let abnf_path = "src/dhall.abnf"; - let visibility_path = "src/dhall.pest.visibility"; - let pest_path = "src/dhall.pest"; - println!("cargo:rerun-if-changed={}", abnf_path); - println!("cargo:rerun-if-changed={}", visibility_path); - - let mut file = File::open(abnf_path)?; - let mut data = Vec::new(); - file.read_to_end(&mut data)?; - data.push('\n' as u8); - - let mut rules = abnf_to_pest::parse_abnf(&data)?; - for line in BufReader::new(File::open(visibility_path)?).lines() { - let line = line?; - if line.len() >= 2 && &line[0..2] == "# " { - rules.get_mut(&line[2..]).map(|x| x.silent = true); - } - } - - let mut file = File::create(pest_path)?; - writeln!(&mut file, "// AUTO-GENERATED FILE. See build.rs.")?; - - // TODO: this is a cheat; properly support RFC3986 URLs instead - rules.remove("url_path"); - writeln!(&mut file, "url_path = _{{ path }}")?; - - rules.remove("simple_label"); - writeln!( - &mut file, - "simple_label = {{ - keyword ~ simple_label_next_char+ - | !keyword ~ simple_label_first_char ~ simple_label_next_char* - }}" - )?; - - rules.remove("nonreserved_label"); - writeln!( - &mut file, - "nonreserved_label = _{{ - !(builtin ~ !simple_label_next_char) ~ label - }}" - )?; - - // Setup grammar for precedence climbing - rules.remove("operator_expression"); - writeln!(&mut file, r##" - import_alt = {{ "?" ~ whsp1 }} - bool_or = {{ "||" }} - natural_plus = {{ "+" ~ whsp1 }} - text_append = {{ "++" }} - list_append = {{ "#" }} - bool_and = {{ "&&" }} - natural_times = {{ "*" }} - bool_eq = {{ "==" }} - bool_ne = {{ "!=" }} - - operator = _{{ - equivalent | - bool_ne | - bool_eq | - natural_times | - combine_types | - prefer | - combine | - bool_and | - list_append | - text_append | - natural_plus | - bool_or | - import_alt - }} - operator_expression = {{ application_expression ~ (whsp ~ operator ~ whsp ~ application_expression)* }} - "##)?; - - writeln!( - &mut file, - "final_expression = ${{ SOI ~ complete_expression ~ EOI }}" - )?; - - writeln!(&mut file)?; - writeln!(&mut file, "{}", render_rules_to_pest(rules).pretty(80))?; - - Ok(()) -} diff --git a/dhall_generated_parser/src/lib.rs b/dhall_generated_parser/src/lib.rs deleted file mode 100644 index fbb9ccd..0000000 --- a/dhall_generated_parser/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! This crate only contains a [pest][pest]-generated parser for the [dhall][dhall] language. -//! It is part of the [dhall-rust][dhall-rust] crate. -//! -//! [pest]: https://pest.rs -//! [dhall]: https://dhall-lang.org/ -//! [dhall-rust]: https://github.com/Nadrieril/dhall-rust - -// This crate only contains the grammar-generated parser. The rest of the -// parser is in dhall_syntax. This separation is because compiling the -// grammar-generated parser is extremely slow. -// See the https://pest.rs documentation for details on what this crate contains. -// The pest file is auto-generated and is located at ./dhall.pest. -// It is generated from grammar.abnf in a rather straightforward manner. Some -// additional overrides are done in ../build.rs. -// The lines that are commented out in ./dhall.pest.visibility are marked as -// silent (see pest docs for what that means) in the generated pest file. - -use pest_derive::Parser; - -#[derive(Parser)] -#[grammar = "dhall.pest"] -pub struct DhallParser; diff --git a/dhall_syntax/Cargo.toml b/dhall_syntax/Cargo.toml deleted file mode 100644 index 2724fa5..0000000 --- a/dhall_syntax/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "dhall_syntax" -version = "0.1.0" -authors = ["NanoTech <nanotech@nanotechcorp.net>", "Nadrieril <nadrieril@users.noreply.github.com>"] -license = "BSD-2-Clause" -edition = "2018" - -[lib] -doctest = false - -[dependencies] -itertools = "0.8.0" -percent-encoding = "2.1.0" -pest = "2.1" -either = "1.5.2" -take_mut = "0.2.2" -hex = "0.3.2" -lazy_static = "1.4.0" -dhall_generated_parser = { path = "../dhall_generated_parser" } -# pest_consume = { path = "../../pest_consume/pest_consume" } -pest_consume = "1.0" diff --git a/dhall_syntax/src/lib.rs b/dhall_syntax/src/lib.rs deleted file mode 100644 index b8fa19f..0000000 --- a/dhall_syntax/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![feature(trace_macros)] -#![feature(never_type)] -#![allow( - clippy::many_single_char_names, - clippy::should_implement_trait, - clippy::new_without_default, - clippy::type_complexity -)] - -//! This crate contains the core AST-handling primitives for the [dhall-rust][dhall-rust] crate. -//! This is highly unstable and breaks regularly; use at your own risk. -//! -//! [dhall-rust]: https://github.com/Nadrieril/dhall-rust - -mod core; -pub use crate::core::context; -pub use crate::core::visitor; -pub use crate::core::*; -mod printer; -pub use crate::printer::*; -mod parser; -pub use crate::parser::*; diff --git a/serde_dhall/Cargo.toml b/serde_dhall/Cargo.toml index c61ddcd..9d46822 100644 --- a/serde_dhall/Cargo.toml +++ b/serde_dhall/Cargo.toml @@ -8,5 +8,4 @@ edition = "2018" [dependencies] serde = { version = "1.0", features = ["derive"] } dhall = { path = "../dhall" } -dhall_syntax = { path = "../dhall_syntax" } dhall_proc_macros = { path = "../dhall_proc_macros" } diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index d371d6d..80ebaf8 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -122,8 +122,8 @@ pub use value::Value; // A Dhall value. pub mod value { - use dhall::phase::{NormalizedExpr, Parsed, Typed}; - use dhall_syntax::Builtin; + use dhall::semantics::phase::{NormalizedExpr, Parsed, Typed}; + use dhall::syntax::Builtin; use super::de::{Error, Result}; @@ -138,7 +138,7 @@ pub mod value { fn from_str_using_dhall_error_type( s: &str, ty: Option<&Value>, - ) -> dhall::error::Result<Self> { + ) -> dhall::semantics::error::Result<Self> { let resolved = Parsed::parse_str(s)?.resolve()?; let typed = match ty { None => resolved.typecheck()?, @@ -193,7 +193,7 @@ pub mod de { pub use error::{Error, Result}; mod error { - use dhall::error::Error as DhallError; + use dhall::semantics::error::Error as DhallError; pub type Result<T> = std::result::Result<T, Error>; diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 26708c1..9006a08 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; -use dhall::phase::NormalizedExpr; -use dhall_syntax::ExprF; +use dhall::semantics::phase::NormalizedExpr; +use dhall::syntax::ExprF; use crate::de::{Deserialize, Error, Result}; use crate::Value; diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs index 67a7bc4..1323aa3 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -1,4 +1,4 @@ -use dhall_syntax::{Builtin, Integer, Natural}; +use dhall::syntax::{Builtin, Integer, Natural}; use crate::Value; |