diff options
Diffstat (limited to 'dhall_syntax/src')
-rw-r--r-- | dhall_syntax/src/core/expr.rs | 17 | ||||
-rw-r--r-- | dhall_syntax/src/core/import.rs | 62 | ||||
-rw-r--r-- | dhall_syntax/src/core/visitor.rs | 4 | ||||
-rw-r--r-- | dhall_syntax/src/parser.rs | 28 | ||||
-rw-r--r-- | dhall_syntax/src/printer.rs | 13 |
5 files changed, 80 insertions, 44 deletions
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<SubExpr, Embed> { /// `e.{ x, y, z }` Projection(SubExpr, DupTreeSet<Label>), /// `./some/path` - Import(Import), + Import(Import<SubExpr>), /// Embeds the result of resolving an import Embed(Embed), } @@ -323,7 +323,7 @@ impl<SE, E> ExprF<SE, E> { impl<E> Expr<E> { pub fn traverse_resolve<E2, Err>( &self, - visit_import: impl FnMut(&Import) -> Result<E2, Err>, + visit_import: impl FnMut(&Import<SubExpr<E2>>) -> Result<E2, Err>, ) -> Result<Expr<E2>, Err> { self.traverse_resolve_with_visitor(&mut visitor::ResolveVisitor( visit_import, @@ -335,15 +335,20 @@ impl<E> Expr<E> { visitor: &mut visitor::ResolveVisitor<F1>, ) -> Result<Expr<E2>, Err> where - F1: FnMut(&Import) -> Result<E2, Err>, + F1: FnMut(&Import<SubExpr<E2>>) -> Result<E2, Err>, { match self { ExprF::BinOp(BinOp::ImportAlt, l, r) => l .as_ref() .traverse_resolve_with_visitor(visitor) .or(r.as_ref().traverse_resolve_with_visitor(visitor)), - ExprF::Import(import) => Ok(ExprF::Embed((visitor.0)(import)?)), - _ => self.visit(visitor), + _ => { + let e = self.visit(&mut *visitor)?; + Ok(match &e { + ExprF::Import(import) => ExprF::Embed((visitor.0)(import)?), + _ => e, + }) + } } } } @@ -373,7 +378,7 @@ impl<E> SubExpr<E> { impl<E> SubExpr<E> { pub fn traverse_resolve<E2, Err>( &self, - visit_import: impl FnMut(&Import) -> Result<E2, Err>, + visit_import: impl FnMut(&Import<SubExpr<E2>>) -> Result<E2, Err>, ) -> Result<SubExpr<E2>, Err> { Ok(self.rewrap(self.as_ref().traverse_resolve(visit_import)?)) } diff --git a/dhall_syntax/src/core/import.rs b/dhall_syntax/src/core/import.rs index d41eae2..9329d48 100644 --- a/dhall_syntax/src/core/import.rs +++ b/dhall_syntax/src/core/import.rs @@ -13,21 +13,20 @@ pub enum FilePrefix { /// The location of import (i.e. local vs. remote vs. environment) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ImportLocation { +pub enum ImportLocation<SubExpr> { Local(FilePrefix, Vec<String>), - Remote(URL), + Remote(URL<SubExpr>), Env(String), Missing, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct URL { +pub struct URL<SubExpr> { pub scheme: Scheme, pub authority: String, pub path: Vec<String>, pub query: Option<String>, - // TODO: implement inline headers - pub headers: Option<Box<ImportHashed>>, + pub headers: Option<SubExpr>, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -49,15 +48,54 @@ pub enum Hash { SHA256(Vec<u8>), } +/// Reference to an external resource #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ImportHashed { - pub location: ImportLocation, +pub struct Import<SubExpr> { + pub mode: ImportMode, + pub location: ImportLocation<SubExpr>, pub hash: Option<Hash>, } -/// Reference to an external resource -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Import { - pub mode: ImportMode, - pub location_hashed: ImportHashed, +impl<SE> URL<SE> { + pub fn visit_subexpr<'a, Err, SE2>( + &'a self, + f: impl FnOnce(&'a SE) -> Result<SE2, Err>, + ) -> Result<URL<SE2>, Err> { + let headers = self.headers.as_ref().map(f).transpose()?; + Ok(URL { + scheme: self.scheme, + authority: self.authority.clone(), + path: self.path.clone(), + query: self.query.clone(), + headers, + }) + } +} + +impl<SE> ImportLocation<SE> { + pub fn visit_subexpr<'a, Err, SE2>( + &'a self, + f: impl FnOnce(&'a SE) -> Result<SE2, Err>, + ) -> Result<ImportLocation<SE2>, Err> { + use ImportLocation::*; + Ok(match self { + Local(prefix, path) => Local(prefix.clone(), path.clone()), + Remote(url) => Remote(url.visit_subexpr(f)?), + Env(env) => Env(env.clone()), + Missing => Missing, + }) + } +} + +impl<SE> Import<SE> { + pub fn visit_subexpr<'a, Err, SE2>( + &'a self, + f: impl FnOnce(&'a SE) -> Result<SE2, Err>, + ) -> Result<Import<SE2>, Err> { + Ok(Import { + mode: self.mode, + location: self.location.visit_subexpr(f)?, + hash: self.hash.clone(), + }) + } } diff --git a/dhall_syntax/src/core/visitor.rs b/dhall_syntax/src/core/visitor.rs index f3d9194..7b4ed4b 100644 --- a/dhall_syntax/src/core/visitor.rs +++ b/dhall_syntax/src/core/visitor.rs @@ -153,7 +153,7 @@ where Field(e, l) => Field(v.visit_subexpr(e)?, l.clone()), Projection(e, ls) => Projection(v.visit_subexpr(e)?, ls.clone()), Assert(e) => Assert(v.visit_subexpr(e)?), - Import(a) => Import(a.clone()), + Import(i) => Import(i.visit_subexpr(|e| v.visit_subexpr(e))?), Embed(a) => Embed(v.visit_embed(a)?), }) } @@ -251,7 +251,7 @@ impl<'a, 'b, E, E2, Err, F1> ExprFFallibleVisitor<'a, SubExpr<E>, SubExpr<E2>, E, E2> for &'b mut ResolveVisitor<F1> where - F1: FnMut(&Import) -> Result<E2, Err>, + F1: FnMut(&Import<SubExpr<E2>>) -> Result<E2, Err>, { type Error = Err; diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index a8dd359..8ecd0ab 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -598,7 +598,7 @@ make_parser! { _ => unreachable!(), }); - rule!(http_raw<URL>; children!( + rule!(http_raw<URL<ParsedSubExpr>>; children!( [scheme(sch), authority(auth), path(p)] => URL { scheme: sch, authority: auth, @@ -619,10 +619,10 @@ make_parser! { rule!(query<String>; captured_str!(s) => s.to_owned()); - rule!(http<URL>; children!( + rule!(http<URL<ParsedSubExpr>>; children!( [http_raw(url)] => url, - [http_raw(url), import_hashed(ih)] => - URL { headers: Some(Box::new(ih)), ..url }, + [http_raw(url), expression(e)] => + URL { headers: Some(e), ..url }, )); rule!(env<String>; children!( @@ -654,7 +654,7 @@ make_parser! { token_rule!(missing<()>); - rule!(import_type<ImportLocation>; children!( + rule!(import_type<ImportLocation<ParsedSubExpr>>; children!( [missing(_)] => { ImportLocation::Missing }, @@ -679,33 +679,33 @@ make_parser! { Hash::SHA256(hex::decode(hash).unwrap()) }); - rule!(import_hashed<ImportHashed>; children!( + rule!(import_hashed<crate::Import<ParsedSubExpr>>; children!( [import_type(location)] => - ImportHashed { location, hash: None }, + crate::Import {mode: ImportMode::Code, location, hash: None }, [import_type(location), hash(h)] => - ImportHashed { location, hash: Some(h) }, + crate::Import {mode: ImportMode::Code, location, hash: Some(h) }, )); token_rule!(Text<()>); token_rule!(Location<()>); rule!(import<ParsedSubExpr> as expression; span; children!( - [import_hashed(location_hashed)] => { + [import_hashed(imp)] => { spanned(span, Import(crate::Import { mode: ImportMode::Code, - location_hashed + ..imp })) }, - [import_hashed(location_hashed), Text(_)] => { + [import_hashed(imp), Text(_)] => { spanned(span, Import(crate::Import { mode: ImportMode::RawText, - location_hashed + ..imp })) }, - [import_hashed(location_hashed), Location(_)] => { + [import_hashed(imp), Location(_)] => { spanned(span, Import(crate::Import { mode: ImportMode::Location, - location_hashed + ..imp })) }, )); diff --git a/dhall_syntax/src/printer.rs b/dhall_syntax/src/printer.rs index 5f5f99b..256ea65 100644 --- a/dhall_syntax/src/printer.rs +++ b/dhall_syntax/src/printer.rs @@ -230,7 +230,7 @@ where f.write_str(close) } -impl<SubExpr: Display + Clone> Display for InterpolatedText<SubExpr> { +impl<SubExpr: Display> Display for InterpolatedText<SubExpr> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.write_str("\"")?; for x in self.iter() { @@ -344,10 +344,11 @@ impl Display for Hash { } } } -impl Display for ImportHashed { +impl<SubExpr: Display> Display for Import<SubExpr> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { use FilePrefix::*; use ImportLocation::*; + use ImportMode::*; let fmt_remote_path_component = |s: &str| -> String { use percent_encoding::{ utf8_percent_encode, PATH_SEGMENT_ENCODE_SET, @@ -423,14 +424,6 @@ impl Display for ImportHashed { write!(f, " ")?; hash.fmt(f)?; } - Ok(()) - } -} - -impl Display for Import { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.location_hashed.fmt(f)?; - use ImportMode::*; match self.mode { Code => {} RawText => write!(f, " as Text")?, |