summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dhall/src/binary.rs93
-rw-r--r--dhall/src/imports.rs1
-rw-r--r--dhall/tests/parser.rs14
-rw-r--r--dhall_core/src/import.rs26
-rw-r--r--dhall_core/src/parser.rs80
-rw-r--r--dhall_core/src/printer.rs49
-rw-r--r--dhall_parser/src/dhall.pest.visibility36
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<Expr<X, Import>>;
@@ -180,18 +179,92 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result<ParsedExpr, DecodeError> {
.collect::<Result<_, _>>()?,
)))
}
- [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::<Result<_, _>>()?;
+ 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::<Result<_, _>>()?;
+ 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<String>,
+ // pub headers: Option<ImportHashed>,
+}
+
+#[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<PathBuf>; 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<Scheme>; captured_str!(s) => match s {
+ "http" => Scheme::HTTP,
+ "https" => Scheme::HTTPS,
+ _ => unreachable!(),
+ });
+
+ rule!(http_raw<URL>; 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<String>; captured_str!(s) => s.to_owned());
+
+ rule!(query<String>; captured_str!(s) => s.to_owned());
+
+ // TODO: headers
+ rule!(http<URL>; children!(
+ [http_raw(url)] => url
+ ));
+
+ rule!(env_raw<String>; children!(
+ [bash_environment_variable(s)] => s,
+ [posix_environment_variable(s)] => s,
+ ));
+ rule!(bash_environment_variable<String>; captured_str!(s) => s.to_owned());
+ rule!(posix_environment_variable<String>; captured_str!(s) => s.to_owned());
+
+ rule!(missing_raw<()>; raw_pair!(_) => ());
+
// TODO: other import types
rule!(import_type_raw<ImportLocation>; 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<ParsedExpr>);
+ rule!(Text_raw<()>; raw_pair!(_) => ());
+
rule!(import_raw<ParsedExpr> 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<ParsedExpr> 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