diff options
Diffstat (limited to 'dhall_core')
| -rw-r--r-- | dhall_core/src/import.rs | 26 | ||||
| -rw-r--r-- | dhall_core/src/parser.rs | 80 | ||||
| -rw-r--r-- | dhall_core/src/printer.rs | 49 | 
3 files changed, 129 insertions, 26 deletions
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;  | 
