From 66260f8e386f7a447352bd8ccbda064b00b698bc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 23:44:52 +0200 Subject: Implement inline headers parsing --- dhall/build.rs | 16 +---------- dhall/src/error/mod.rs | 8 +++--- dhall/src/phase/binary.rs | 50 ++++++++++++-------------------- dhall/src/phase/resolve.rs | 8 +++--- dhall_generated_parser/build.rs | 30 +++++++------------ dhall_syntax/src/core/expr.rs | 17 +++++++---- dhall_syntax/src/core/import.rs | 62 ++++++++++++++++++++++++++++++++-------- dhall_syntax/src/core/visitor.rs | 4 +-- dhall_syntax/src/parser.rs | 28 +++++++++--------- dhall_syntax/src/printer.rs | 13 ++------- 10 files changed, 119 insertions(+), 117 deletions(-) diff --git a/dhall/build.rs b/dhall/build.rs index 790ad8e..cbda288 100644 --- a/dhall/build.rs +++ b/dhall/build.rs @@ -93,13 +93,6 @@ fn main() -> std::io::Result<()> { make_test_module(&mut file, "parse", "parser/", "Parser", |path| { // Too slow in debug mode path == "success/largeExpression" - // TODO: Inline headers - || path == "success/unit/import/inlineUsing" - || path == "success/unit/import/Headers" - || path == "success/unit/import/HeadersDoubleHash" - || path == "success/unit/import/HeadersDoubleHashPrecedence" - || path == "success/unit/import/HeadersHashPrecedence" - || path == "success/unit/import/HeadersInteriorHash" // TODO: projection by expression || path == "success/recordProjectionByExpression" || path == "success/RecordProjectionByType" @@ -119,9 +112,6 @@ fn main() -> std::io::Result<()> { path.starts_with("failure/") // Too slow in debug mode || path == "success/largeExpression" - // TODO: Inline headers - || path == "success/unit/import/inlineUsing" - || path == "success/unit/import/Headers" // TODO: projection by expression || path == "success/recordProjectionByExpression" || path == "success/RecordProjectionByType" @@ -149,9 +139,6 @@ fn main() -> std::io::Result<()> { || path == "success/double" || path == "success/unit/DoubleLitExponentNoDot" || path == "success/unit/DoubleLitSecretelyInt" - // TODO: Inline headers - || path == "success/unit/import/inlineUsing" - || path == "success/unit/import/Headers" // TODO: projection by expression || path == "success/recordProjectionByExpression" || path == "success/RecordProjectionByType" @@ -237,10 +224,9 @@ fn main() -> std::io::Result<()> { false // TODO: Enable imports in typecheck tests || path == "failure/importBoundary" + || path == "failure/customHeadersUsingBoundVariable" // Too slow || path == "success/prelude" - // TODO: Inline headers - || path == "failure/customHeadersUsingBoundVariable" // TODO: projection by expression || path == "failure/unit/RecordProjectionByTypeFieldTypeMismatch" || path == "failure/unit/RecordProjectionByTypeNotPresent" diff --git a/dhall/src/error/mod.rs b/dhall/src/error/mod.rs index 3626d96..8f6ff51 100644 --- a/dhall/src/error/mod.rs +++ b/dhall/src/error/mod.rs @@ -4,7 +4,7 @@ use dhall_syntax::{BinOp, Import, Label, ParseError, V}; use crate::core::context::TypecheckContext; use crate::phase::resolve::ImportStack; -use crate::phase::{Normalized, Type, Typed}; +use crate::phase::{Normalized, NormalizedSubExpr, Type, Typed}; pub type Result = std::result::Result; @@ -21,9 +21,9 @@ pub enum Error { #[derive(Debug)] pub enum ImportError { - Recursive(Import, Box), - UnexpectedImport(Import), - ImportCycle(ImportStack, Import), + Recursive(Import, Box), + UnexpectedImport(Import), + ImportCycle(ImportStack, Import), } #[derive(Debug)] diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 9ed823c..36dd471 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -4,9 +4,8 @@ use std::iter::FromIterator; use dhall_syntax::map::DupTreeMap; use dhall_syntax::{ - rc, ExprF, FilePrefix, Hash, Import, ImportHashed, ImportLocation, - ImportMode, Integer, InterpolatedText, Label, Natural, Scheme, SubExpr, - URL, V, + rc, ExprF, FilePrefix, Hash, Import, ImportLocation, ImportMode, Integer, + InterpolatedText, Label, Natural, Scheme, SubExpr, URL, V, }; use crate::error::{DecodeError, EncodeError}; @@ -260,20 +259,12 @@ fn cbor_value_to_dhall( }; let headers = match rest.next() { Some(Null) => None, - // TODO - // Some(x) => { - // match cbor_value_to_dhall(&x)?.as_ref() { - // Import(import) => Some(Box::new( - // import.location_hashed.clone(), - // )), - // _ => Err(DecodeError::WrongFormatError( - // "import/remote/headers".to_owned(), - // ))?, - // } - // } + Some(x) => { + let x = cbor_value_to_dhall(&x)?; + Some(x) + } _ => Err(DecodeError::WrongFormatError( - "import/remote/headers is unimplemented" - .to_owned(), + "import/remote/headers".to_owned(), ))?, }; let authority = match rest.next() { @@ -341,7 +332,8 @@ fn cbor_value_to_dhall( }; Import(dhall_syntax::Import { mode, - location_hashed: ImportHashed { hash, location }, + hash, + location, }) } [U64(25), bindings..] => { @@ -572,14 +564,17 @@ where } } -fn serialize_import(ser: S, import: &Import) -> Result +fn serialize_import( + ser: S, + import: &Import>, +) -> Result where S: serde::ser::Serializer, { use cbor::Value::{Bytes, Null, U64}; use serde::ser::SerializeSeq; - let count = 4 + match &import.location_hashed.location { + let count = 4 + match &import.location { ImportLocation::Remote(url) => 3 + url.path.len(), ImportLocation::Local(_, path) => path.len(), ImportLocation::Env(_) => 1, @@ -589,7 +584,7 @@ where ser_seq.serialize_element(&U64(24))?; - let hash = match &import.location_hashed.hash { + let hash = match &import.hash { None => Null, Some(Hash::SHA256(h)) => { let mut bytes = vec![18, 32]; @@ -606,7 +601,7 @@ where }; ser_seq.serialize_element(&U64(mode))?; - let scheme = match &import.location_hashed.location { + let scheme = match &import.location { ImportLocation::Remote(url) => match url.scheme { Scheme::HTTP => 0, Scheme::HTTPS => 1, @@ -622,19 +617,12 @@ where }; ser_seq.serialize_element(&U64(scheme))?; - match &import.location_hashed.location { + match &import.location { ImportLocation::Remote(url) => { match &url.headers { None => ser_seq.serialize_element(&Null)?, - Some(location_hashed) => { - let e = rc( - ExprF::Import(dhall_syntax::Import { - mode: ImportMode::Code, - location_hashed: location_hashed.as_ref().clone(), - }), - ); - let s: Serialize<'_, ()> = self::Serialize::Expr(&e); - ser_seq.serialize_element(&s)? + Some(e) => { + ser_seq.serialize_element(&self::Serialize::Expr(e))? } }; ser_seq.serialize_element(&url.authority)?; diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index abcee7e..52353e4 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use dhall_syntax::Import; - use crate::error::{Error, ImportError}; -use crate::phase::{Normalized, Parsed, Resolved}; +use crate::phase::{Normalized, NormalizedSubExpr, Parsed, Resolved}; + +type Import = dhall_syntax::Import; /// A root from which to resolve relative imports. #[derive(Debug, Clone, PartialEq, Eq)] @@ -28,7 +28,7 @@ fn resolve_import( let cwd = match root { LocalDir(cwd) => cwd, }; - match &import.location_hashed.location { + match &import.location { Local(prefix, path) => { let path: PathBuf = path.iter().cloned().collect(); let path = match prefix { diff --git a/dhall_generated_parser/build.rs b/dhall_generated_parser/build.rs index 5275097..070aa9c 100644 --- a/dhall_generated_parser/build.rs +++ b/dhall_generated_parser/build.rs @@ -26,16 +26,15 @@ fn main() -> std::io::Result<()> { rules.get_mut(&line[2..]).map(|x| x.silent = true); } } - rules.remove("http"); - rules.remove("url_path"); - rules.remove("simple_label"); - rules.remove("nonreserved_label"); let mut file = File::create(pest_path)?; writeln!(&mut file, "// AUTO-GENERATED FILE. See build.rs.")?; - writeln!(&mut file, "{}", render_rules_to_pest(rules).pretty(80))?; - writeln!(&mut file)?; + // 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 = {{ @@ -43,30 +42,23 @@ fn main() -> std::io::Result<()> { | !keyword ~ simple_label_first_char ~ simple_label_next_char* }}" )?; - // TODO: this is a cheat; actually implement inline headers instead - writeln!( - &mut file, - "http = {{ - http_raw - ~ (whsp - ~ using - ~ whsp1 - ~ (import_hashed | ^\"(\" ~ whsp ~ import_hashed ~ whsp ~ ^\")\"))? - }}" - )?; - // TODO: this is a cheat; properly support RFC3986 URLs instead - writeln!(&mut file, "url_path = _{{ path }}")?; + + rules.remove("nonreserved_label"); writeln!( &mut file, "nonreserved_label = _{{ !(builtin ~ !simple_label_next_char) ~ label }}" )?; + writeln!( &mut file, "final_expression = ${{ SOI ~ complete_expression ~ EOI }}" )?; + writeln!(&mut file)?; + writeln!(&mut file, "{}", render_rules_to_pest(rules).pretty(80))?; + // Generate pest parser manually to avoid spurious recompilations let derived = { let pest_path = "dhall.pest"; diff --git a/dhall_syntax/src/core/expr.rs b/dhall_syntax/src/core/expr.rs index 9729efb..30ac4eb 100644 --- a/dhall_syntax/src/core/expr.rs +++ b/dhall_syntax/src/core/expr.rs @@ -258,7 +258,7 @@ pub enum ExprF { /// `e.{ x, y, z }` Projection(SubExpr, DupTreeSet