From fe38fd6a8859447a154a5698a3e21d9203262be2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 22 Mar 2019 00:01:30 +0100 Subject: Parse a lot more of the import types --- dhall/src/binary.rs | 93 ++++++++++++++++++++++++++++++---- dhall/src/imports.rs | 1 + dhall/tests/parser.rs | 14 ++--- dhall_core/src/import.rs | 26 ++++++++-- dhall_core/src/parser.rs | 80 +++++++++++++++++++++-------- dhall_core/src/printer.rs | 49 +++++++++++++++++- dhall_parser/src/dhall.pest.visibility | 36 ++++++------- 7 files changed, 238 insertions(+), 61 deletions(-) diff --git a/dhall/src/binary.rs b/dhall/src/binary.rs index 8fe66f5..a028e82 100644 --- a/dhall/src/binary.rs +++ b/dhall/src/binary.rs @@ -1,7 +1,6 @@ use dhall_core::*; use itertools::*; use serde_cbor::value::value as cbor; -use std::path::PathBuf; use std::rc::Rc; type ParsedExpr = Rc>; @@ -180,18 +179,92 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { .collect::>()?, ))) } - [U64(24), Null, U64(0), U64(3), rest..] => { - let mut path = PathBuf::new(); - for s in rest { - match s { - String(s) => path.push(s), - _ => Err(DecodeError::WrongFormatError)?, + [U64(24), _hash, U64(mode), U64(scheme), rest..] => { + let mode = match mode { + 1 => ImportMode::RawText, + _ => ImportMode::Code, + }; + let mut rest = rest.iter(); + let location = match scheme { + 0 | 1 => { + let scheme = match scheme { + 0 => Scheme::HTTP, + _ => Scheme::HTTPS, + }; + let _headers = match rest.next() { + Some(Null) => (), + _ => Err(DecodeError::WrongFormatError( + "import/remote/headers".to_owned(), + ))?, + }; + let authority = match rest.next() { + Some(String(s)) => s.to_owned(), + _ => Err(DecodeError::WrongFormatError( + "import/remote/authority".to_owned(), + ))?, + }; + let query = match rest.next_back() { + Some(Null) => None, + Some(String(s)) => Some(s.to_owned()), + _ => Err(DecodeError::WrongFormatError( + "import/remote/query".to_owned(), + ))?, + }; + let path = rest + .map(|s| { + s.as_string().ok_or( + DecodeError::WrongFormatError( + "import/remote/path".to_owned(), + ), + ) + }) + .collect::>()?; + ImportLocation::Remote(URL { + scheme, + authority, + path, + query, + }) } - } + 2 | 3 | 4 | 5 => { + let prefix = match scheme { + 2 => FilePrefix::Absolute, + 3 => FilePrefix::Here, + 4 => FilePrefix::Parent, + 5 => FilePrefix::Home, + _ => Err(DecodeError::WrongFormatError( + "import/local/prefix".to_owned(), + ))?, + }; + let path = rest + .map(|s| { + s.as_string().ok_or( + DecodeError::WrongFormatError( + "import/local/path".to_owned(), + ), + ) + }) + .collect::>()?; + ImportLocation::Local(prefix, path) + } + 6 => { + let env = match rest.next() { + Some(String(s)) => s.to_owned(), + _ => Err(DecodeError::WrongFormatError( + "import/env".to_owned(), + ))?, + }; + ImportLocation::Env(env) + } + 7 => ImportLocation::Missing, + _ => Err(DecodeError::WrongFormatError( + "import/type".to_owned(), + ))?, + }; Embed(Import { - mode: ImportMode::Code, + mode, hash: None, - location: ImportLocation::Local(FilePrefix::Here, path), + location, }) } [U64(25), bindings..] => { diff --git a/dhall/src/imports.rs b/dhall/src/imports.rs index 9f60ee7..8a2edce 100644 --- a/dhall/src/imports.rs +++ b/dhall/src/imports.rs @@ -38,6 +38,7 @@ fn resolve_import( }; load_dhall_file(&path, true) } + _ => unimplemented!("{:?}", import), } } diff --git a/dhall/tests/parser.rs b/dhall/tests/parser.rs index 79a059d..637341d 100644 --- a/dhall/tests/parser.rs +++ b/dhall/tests/parser.rs @@ -14,13 +14,13 @@ macro_rules! parser_failure { } parser_success!(spec_parser_success_annotations, "annotations"); -// parser_success!(spec_parser_success_asText, "asText"); +parser_success!(spec_parser_success_asText, "asText"); parser_success!(spec_parser_success_blockComment, "blockComment"); parser_success!(spec_parser_success_builtins, "builtins"); parser_success!(spec_parser_success_collectionImportType, "collectionImportType"); parser_success!(spec_parser_success_double, "double"); parser_success!(spec_parser_success_doubleQuotedString, "doubleQuotedString"); -// parser_success!(spec_parser_success_environmentVariables, "environmentVariables"); +parser_success!(spec_parser_success_environmentVariables, "environmentVariables"); // parser_success!(spec_parser_success_escapedDoubleQuotedString, "escapedDoubleQuotedString"); parser_success!(spec_parser_success_escapedSingleQuotedString, "escapedSingleQuotedString"); parser_success!(spec_parser_success_fields, "fields"); @@ -28,7 +28,7 @@ parser_success!(spec_parser_success_forall, "forall"); parser_success!(spec_parser_success_functionType, "functionType"); parser_success!(spec_parser_success_identifier, "identifier"); parser_success!(spec_parser_success_ifThenElse, "ifThenElse"); -// parser_success!(spec_parser_success_importAlt, "importAlt"); +parser_success!(spec_parser_success_importAlt, "importAlt"); parser_success!(spec_parser_success_interpolatedDoubleQuotedString, "interpolatedDoubleQuotedString"); parser_success!(spec_parser_success_interpolatedSingleQuotedString, "interpolatedSingleQuotedString"); parser_success!(spec_parser_success_label, "label"); @@ -43,10 +43,10 @@ parser_success!(spec_parser_success_natural, "natural"); parser_success!(spec_parser_success_nestedBlockComment, "nestedBlockComment"); parser_success!(spec_parser_success_operators, "operators"); // parser_success!(spec_parser_success_parenthesizeUsing, "parenthesizeUsing"); -// parser_success!(spec_parser_success_pathTermination, "pathTermination"); -// parser_success!(spec_parser_success_paths, "paths"); +parser_success!(spec_parser_success_pathTermination, "pathTermination"); +parser_success!(spec_parser_success_paths, "paths"); // parser_success!(spec_parser_success_quotedLabel, "quotedLabel"); -// parser_success!(spec_parser_success_quotedPaths, "quotedPaths"); +parser_success!(spec_parser_success_quotedPaths, "quotedPaths"); parser_success!(spec_parser_success_record, "record"); parser_success!(spec_parser_success_reservedPrefix, "reservedPrefix"); parser_success!(spec_parser_success_singleQuotedString, "singleQuotedString"); @@ -54,7 +54,7 @@ parser_success!(spec_parser_success_sort, "sort"); parser_success!(spec_parser_success_template, "template"); parser_success!(spec_parser_success_unicodeComment, "unicodeComment"); parser_success!(spec_parser_success_unicodeDoubleQuotedString, "unicodeDoubleQuotedString"); -// parser_success!(spec_parser_success_unicodePaths, "unicodePaths"); +parser_success!(spec_parser_success_unicodePaths, "unicodePaths"); parser_success!(spec_parser_success_union, "union"); // parser_success!(spec_parser_success_urls, "urls"); parser_success!(spec_parser_success_whitespace, "whitespace"); diff --git a/dhall_core/src/import.rs b/dhall_core/src/import.rs index 3e2fbe8..21bd370 100644 --- a/dhall_core/src/import.rs +++ b/dhall_core/src/import.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; /// The beginning of a file path which anchors subsequent path components -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum FilePrefix { /// Absolute path Absolute, @@ -17,15 +17,31 @@ pub enum FilePrefix { #[derive(Debug, Clone, PartialEq, Eq)] pub enum ImportLocation { Local(FilePrefix, PathBuf), - // TODO: other import types + Remote(URL), + Env(String), + Missing, } -/// How to interpret the import's contents (i.e. as Dhall code or raw text) #[derive(Debug, Clone, PartialEq, Eq)] +pub struct URL { + pub scheme: Scheme, + pub authority: String, + pub path: PathBuf, + pub query: Option, + // pub headers: Option, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Scheme { + HTTP, + HTTPS, +} + +/// How to interpret the import's contents (i.e. as Dhall code or raw text) +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ImportMode { Code, - // TODO - // RawText, + RawText, } /// Reference to an external resource diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index 865e791..165b393 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -377,11 +377,7 @@ make_parser! { )); rule!(path; children!( [path_component(components..)] => { - let mut path = PathBuf::new(); - for s in components { - path.push(s); - } - path + components.collect() } )); @@ -390,33 +386,69 @@ make_parser! { rule!(parent_path<(FilePrefix, PathBuf)> as local_raw; children!( [path(p)] => (FilePrefix::Parent, p) )); - rule!(here_path<(FilePrefix, PathBuf)> as local_raw; children!( [path(p)] => (FilePrefix::Here, p) )); - rule!(home_path<(FilePrefix, PathBuf)> as local_raw; children!( [path(p)] => (FilePrefix::Home, p) )); - rule!(absolute_path<(FilePrefix, PathBuf)> as local_raw; children!( [path(p)] => (FilePrefix::Absolute, p) )); + rule!(scheme; captured_str!(s) => match s { + "http" => Scheme::HTTP, + "https" => Scheme::HTTPS, + _ => unreachable!(), + }); + + rule!(http_raw; children!( + [scheme(sch), authority(auth), path(p)] => URL { + scheme: sch, + authority: auth, + path: p, + query: None, + }, + [scheme(sch), authority(auth), path(p), query(q)] => URL { + scheme: sch, + authority: auth, + path: p, + query: Some(q), + }, + )); + + rule!(authority; captured_str!(s) => s.to_owned()); + + rule!(query; captured_str!(s) => s.to_owned()); + + // TODO: headers + rule!(http; children!( + [http_raw(url)] => url + )); + + rule!(env_raw; children!( + [bash_environment_variable(s)] => s, + [posix_environment_variable(s)] => s, + )); + rule!(bash_environment_variable; captured_str!(s) => s.to_owned()); + rule!(posix_environment_variable; captured_str!(s) => s.to_owned()); + + rule!(missing_raw<()>; raw_pair!(_) => ()); + // TODO: other import types rule!(import_type_raw; children!( - // [missing_raw(_e)] => { - // ImportLocation::Missing - // } - // [env_raw(e)] => { - // ImportLocation::Env(e) - // } - // [http(url)] => { - // ImportLocation::Remote(url) - // } + [missing_raw(_)] => { + ImportLocation::Missing + }, + [env_raw(e)] => { + ImportLocation::Env(e) + }, + [http(url)] => { + ImportLocation::Remote(url) + }, [local_raw((prefix, path))] => { ImportLocation::Local(prefix, path) - } + }, )); rule!(import_hashed_raw<(ImportLocation, Option<()>)>; children!( @@ -426,15 +458,23 @@ make_parser! { rule_group!(expression); + rule!(Text_raw<()>; raw_pair!(_) => ()); + rule!(import_raw as expression; children!( - // TODO: handle "as Text" [import_hashed_raw((location, hash))] => { bx(Expr::Embed(Import { mode: ImportMode::Code, hash, location, })) - } + }, + [import_hashed_raw((location, hash)), Text_raw(_)] => { + bx(Expr::Embed(Import { + mode: ImportMode::RawText, + hash, + location, + })) + }, )); rule!(lambda_expression as expression; children!( diff --git a/dhall_core/src/printer.rs b/dhall_core/src/printer.rs index bd38863..7b108d5 100644 --- a/dhall_core/src/printer.rs +++ b/dhall_core/src/printer.rs @@ -1,4 +1,5 @@ use crate::*; +use itertools::Itertools; use std::fmt::{self, Display}; // There used to be a one-to-one correspondence between the formatters in this section @@ -286,8 +287,25 @@ impl Display for Const { impl Display for Import { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use std::path::PathBuf; use FilePrefix::*; use ImportLocation::*; + use ImportMode::*; + let quoted = |s: &str| -> String { + if s.chars().all(|c| c.is_ascii_alphanumeric()) { + s.to_owned() + } else { + format!("\"{}\"", s) + } + }; + let fmt_path = |f: &mut fmt::Formatter, p: &PathBuf| { + let res: String = p + .iter() + .map(|c| quoted(c.to_string_lossy().as_ref())) + .join("/"); + f.write_str(&res) + }; + match &self.location { Local(prefix, path) => { let prefix = match prefix { @@ -296,9 +314,28 @@ impl Display for Import { Home => "~", Absolute => "", }; - write!(f, "{}/{}", prefix, path.to_str().unwrap()) + write!(f, "{}/", prefix)?; + fmt_path(f, path)?; + } + Remote(url) => { + write!(f, "{}://{}/", url.scheme, url.authority,)?; + fmt_path(f, &url.path)?; + if let Some(q) = &url.query { + write!(f, "?{}", q)? + } } + Env(e) => { + write!(f, "env:{}", quoted(e))?; + } + Missing => { + write!(f, "missing")?; + } + } + match self.mode { + Code => {} + RawText => write!(f, " as Text")?, } + Ok(()) } } @@ -339,6 +376,16 @@ impl Display for Builtin { } } +impl Display for Scheme { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use crate::Scheme::*; + f.write_str(match *self { + HTTP => "http", + HTTPS => "https", + }) + } +} + impl Display for V { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { let V(ref x, ref n) = *self; diff --git a/dhall_parser/src/dhall.pest.visibility b/dhall_parser/src/dhall.pest.visibility index 00075d3..3d0a80c 100644 --- a/dhall_parser/src/dhall.pest.visibility +++ b/dhall_parser/src/dhall.pest.visibility @@ -35,9 +35,9 @@ single_quote_literal # as_raw # using_raw # merge_raw -# missing_raw +missing_raw # Optional_raw -# Text_raw +Text_raw # List_raw # Infinity_raw # if_ @@ -98,28 +98,28 @@ path scheme http_raw authority -userinfo -host -port -IP_literal -IPvFuture -IPv6address -h16 -ls32 -IPv4address -dec_octet -reg_name -pchar +# userinfo +# host +# port +# IP_literal +# IPvFuture +# IPv6address +# h16 +# ls32 +# IPv4address +# dec_octet +# reg_name +# pchar query fragment -pct_encoded -unreserved -sub_delims +# pct_encoded +# unreserved +# sub_delims http env_raw bash_environment_variable posix_environment_variable -posix_environment_variable_character +# posix_environment_variable_character import_type_raw hash_raw import_hashed_raw -- cgit v1.2.3