From 54382cd107d1befd6015f8232716158a20db44a4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 6 Mar 2019 23:35:39 +0100 Subject: Start parsing imports --- dhall/src/imports.rs | 11 +++++ dhall/src/lib.rs | 2 +- dhall/src/main.rs | 4 +- dhall/src/normalize.rs | 2 +- dhall/tests/tests.rs | 2 +- dhall_core/src/core.rs | 83 ++++++++++++++++++++++++++++------ dhall_core/src/grammar_util.rs | 4 +- dhall_core/src/parser.rs | 65 +++++++++++++++++++++++++- dhall_generator/src/lib.rs | 4 +- dhall_parser/src/dhall.abnf | 13 ++++-- dhall_parser/src/dhall.pest.visibility | 2 +- 11 files changed, 162 insertions(+), 30 deletions(-) create mode 100644 dhall/src/imports.rs diff --git a/dhall/src/imports.rs b/dhall/src/imports.rs new file mode 100644 index 0000000..32ddfd7 --- /dev/null +++ b/dhall/src/imports.rs @@ -0,0 +1,11 @@ +use dhall_core::{Expr, Import, ImportLocation, ImportMode, FilePrefix, X}; + + +// fn resolve_import(import: Import) -> Expr { + +// } + +pub fn resolve_imports<'i, S: Clone>(expr: &Expr<'i, S, Import>) -> Expr<'i, S, X> { + let no_import = |_: &Import| -> X { panic!("ahhh import") }; + expr.map_embed(&no_import) +} diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index 58b29a3..54f0983 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -5,4 +5,4 @@ mod normalize; pub use crate::normalize::*; pub mod typecheck; - +pub mod imports; diff --git a/dhall/src/main.rs b/dhall/src/main.rs index 3e8aca4..43d03ce 100644 --- a/dhall/src/main.rs +++ b/dhall/src/main.rs @@ -91,9 +91,7 @@ fn main() { } }; - /* - expr' <- load expr - */ + let expr = imports::resolve_imports(&expr); let type_expr = match typecheck::type_of(&expr) { Err(e) => { diff --git a/dhall/src/normalize.rs b/dhall/src/normalize.rs index ec594da..b46722a 100644 --- a/dhall/src/normalize.rs +++ b/dhall/src/normalize.rs @@ -145,7 +145,7 @@ where }, // Normalize everything else before matching - e => match e.map_shallow(normalize, |_| unreachable!()) { + e => match e.map_shallow(normalize, |_| unreachable!(), |x| x.clone()) { BinOp(BoolAnd, box BoolLit(x), box BoolLit(y)) => BoolLit(x && y), BinOp(BoolOr, box BoolLit(x), box BoolLit(y)) => BoolLit(x || y), BinOp(BoolEQ, box BoolLit(x), box BoolLit(y)) => BoolLit(x == y), diff --git a/dhall/tests/tests.rs b/dhall/tests/tests.rs index a523b6e..8b910a2 100644 --- a/dhall/tests/tests.rs +++ b/dhall/tests/tests.rs @@ -14,7 +14,7 @@ make_spec_test!(normalization, spec_normalization_success_haskell_tutorial_acces // make_spec_test!(normalization, spec_normalization_success_multiline_preserveComment, "normalization/success/multiline/preserveComment"); // make_spec_test!(normalization, spec_normalization_success_multiline_singleLine, "normalization/success/multiline/singleLine"); // make_spec_test!(normalization, spec_normalization_success_multiline_twoLines, "normalization/success/multiline/twoLines"); -// make_spec_test!(normalization, spec_normalization_success_prelude_Bool_and_0, "normalization/success/prelude/Bool/and/0"); +make_spec_test!(normalization, spec_normalization_success_prelude_Bool_and_0, "normalization/success/prelude/Bool/and/0"); // make_spec_test!(normalization, spec_normalization_success_prelude_Bool_and_1, "normalization/success/prelude/Bool/and/1"); // make_spec_test!(normalization, spec_normalization_success_prelude_Bool_build_0, "normalization/success/prelude/Bool/build/0"); // make_spec_test!(normalization, spec_normalization_success_prelude_Bool_build_1, "normalization/success/prelude/Bool/build/1"); diff --git a/dhall_core/src/core.rs b/dhall_core/src/core.rs index fcb7713..cb4d6ca 100644 --- a/dhall_core/src/core.rs +++ b/dhall_core/src/core.rs @@ -24,17 +24,47 @@ use std::path::PathBuf; /// Note that Dhall does not support functions from terms to types and therefore /// Dhall is not a dependently typed language /// -#[derive(Debug, Copy, Clone, PartialEq, Eq)] // (Show, Bounded, Enum) +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Const { Type, Kind, } -/// Path to an external resource -#[derive(Debug, Clone, PartialEq, Eq)] // (Eq, Ord, Show) -pub enum Path { - File(PathBuf), - URL(String), +/// The beginning of a file path which anchors subsequent path components +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum FilePrefix { + /// Absolute path + Absolute, + /// Path relative to . + Here, + /// Path relative to .. + Parent, + /// Path relative to ~ + Home, +} + +/// The location of import (i.e. local vs. remote vs. environment) +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ImportLocation { + Local(FilePrefix, PathBuf), + // TODO: other import types +} + +/// How to interpret the import's contents (i.e. as Dhall code or raw text) +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ImportMode { + Code, + // TODO + // RawText, +} + +/// Reference to an external resource +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Import { + pub mode: ImportMode, + pub location: ImportLocation, + // TODO + pub hash: Option<()>, } /// Label for a bound variable @@ -231,19 +261,34 @@ impl<'i, S, A> From for Expr<'i, S, A> { } impl<'i, S, A> Expr<'i, S, A> { - pub fn map_shallow( + pub fn map_shallow( &self, map_expr: F1, map_note: F2, - ) -> Expr<'i, T, A> + map_embed: F3, + ) -> Expr<'i, T, B> where A: Clone, T: Clone, S: Clone, - F1: Fn(&Self) -> Expr<'i, T, A>, + F1: Fn(&Self) -> Expr<'i, T, B>, F2: FnOnce(&S) -> T, + F3: FnOnce(&A) -> B, + { + map_shallow(self, map_expr, map_note, map_embed) + } + + pub fn map_embed( + &self, + map_embed: &F, + ) -> Expr<'i, S, B> + where + A: Clone, + S: Clone, + F: Fn(&A) -> B, { - map_shallow(self, map_expr, map_note) + let recurse = |e: &Expr<'i, S, A>| -> Expr<'i, S, B> { e.map_embed(map_embed) }; + map_shallow(self, recurse, |x| x.clone(), map_embed) } pub fn bool_lit(&self) -> Option { @@ -512,6 +557,12 @@ impl Display for Const { } } +impl Display for Import { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + ::fmt(self, f) + } +} + impl Display for Builtin { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { use crate::Builtin::*; @@ -643,20 +694,22 @@ fn add_ui(u: usize, i: isize) -> usize { } } -pub fn map_shallow<'i, S, T, A, F1, F2>( +pub fn map_shallow<'i, S, T, A, B, F1, F2, F3>( e: &Expr<'i, S, A>, map: F1, map_note: F2, -) -> Expr<'i, T, A> + map_embed: F3, +) -> Expr<'i, T, B> where A: Clone, S: Clone, T: Clone, - F1: Fn(&Expr<'i, S, A>) -> Expr<'i, T, A>, + F1: Fn(&Expr<'i, S, A>) -> Expr<'i, T, B>, F2: FnOnce(&S) -> T, + F3: FnOnce(&A) -> B, { use crate::Expr::*; - let bxmap = |x: &Expr<'i, S, A>| -> Box> { bx(map(x)) }; + let bxmap = |x: &Expr<'i, S, A>| -> Box> { bx(map(x)) }; let opt = |x| map_opt_box(x, &map); match *e { Const(k) => Const(k), @@ -691,7 +744,7 @@ where Merge(ref x, ref y, ref t) => Merge(bxmap(x), bxmap(y), opt(t)), Field(ref r, x) => Field(bxmap(r), x), Note(ref n, ref e) => Note(map_note(n), bxmap(e)), - Embed(ref a) => Embed(a.clone()), + Embed(ref a) => Embed(map_embed(a)), } } diff --git a/dhall_core/src/grammar_util.rs b/dhall_core/src/grammar_util.rs index ce73444..82528f4 100644 --- a/dhall_core/src/grammar_util.rs +++ b/dhall_core/src/grammar_util.rs @@ -1,6 +1,6 @@ -use crate::core::{Expr, X}; +use crate::core::{Expr, X, Import}; -pub type ParsedExpr<'i> = Expr<'i, X, X>; // FIXME Parse paths and replace the second X with Path +pub type ParsedExpr<'i> = Expr<'i, X, Import>; pub type BoxExpr<'i> = Box>; pub type ExprOpFn<'i> = fn(BoxExpr<'i>, BoxExpr<'i>) -> ParsedExpr<'i>; pub type ExprListFn<'i> = diff --git a/dhall_core/src/parser.rs b/dhall_core/src/parser.rs index f5a9129..09863a2 100644 --- a/dhall_core/src/parser.rs +++ b/dhall_core/src/parser.rs @@ -3,11 +3,12 @@ use std::collections::BTreeMap; use lalrpop_util; use pest::iterators::Pair; use pest::Parser; +use std::path::PathBuf; use dhall_parser::{DhallParser, Rule}; use crate::core; -use crate::core::{bx, BinOp, Builtin, Const, Expr, V}; +use crate::core::*; use crate::grammar; use crate::grammar_util::{BoxExpr, ParsedExpr}; use crate::lexer::{Lexer, LexicalError, Tok}; @@ -496,6 +497,67 @@ rule!(integer_literal_raw; } ); +rule!(path; captured_str!(s) => s.into()); + +rule!(parent_path<(FilePrefix, PathBuf)>; + children!(p: path) => (FilePrefix::Parent, p) +); + +rule!(here_path<(FilePrefix, PathBuf)>; + children!(p: path) => (FilePrefix::Here, p) +); + +rule!(home_path<(FilePrefix, PathBuf)>; + children!(p: path) => (FilePrefix::Home, p) +); + +rule!(absolute_path<(FilePrefix, PathBuf)>; + children!(p: path) => (FilePrefix::Absolute, p) +); + +rule_group!(local_raw<(FilePrefix, PathBuf)>; + parent_path, + here_path, + home_path, + absolute_path +); + +// TODO: other import types +rule!(import_type_raw; + // children!(_e: missing_raw) => { + // ImportLocation::Missing + // } + // children!(e: env_raw) => { + // ImportLocation::Env(e) + // } + // children!(url: http) => { + // ImportLocation::Remote(url) + // } + children!(import: local_raw) => { + let (prefix, path) = import; + ImportLocation::Local(prefix, path) + } +); + +rule!(import_hashed_raw<(ImportLocation, Option<()>)>; + // TODO: handle hash + children!(import: import_type_raw) => { + (import, None) + } +); + +rule!(import_raw>; + // TODO: handle "as Text" + children!(import: import_hashed_raw) => { + let (location, hash) = import; + bx(Expr::Embed(Import { + mode: ImportMode::Code, + hash, + location, + })) + } +); + rule_group!(expression>; identifier_raw, lambda_expression, @@ -522,6 +584,7 @@ rule_group!(expression>; not_equal_expression, application_expression, + import_raw, selector_expression_raw, literal_expression_raw, empty_record_type, diff --git a/dhall_generator/src/lib.rs b/dhall_generator/src/lib.rs index 5b3cc6f..b26ea63 100644 --- a/dhall_generator/src/lib.rs +++ b/dhall_generator/src/lib.rs @@ -8,7 +8,9 @@ use quote::quote; #[proc_macro] pub fn dhall(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input_str = input.to_string(); - let expr = parser::parse_expr_pest(&input_str).unwrap(); + let expr: Box> = parser::parse_expr_pest(&input_str).unwrap(); + let no_import = |_: &Import| -> X { panic!("Don't use import in dhall!()") }; + let expr = expr.map_embed(&no_import); let output = dhall_to_tokenstream(&expr, &Context::new()); output.into() } diff --git a/dhall_parser/src/dhall.abnf b/dhall_parser/src/dhall.abnf index 76af24b..d803770 100644 --- a/dhall_parser/src/dhall.abnf +++ b/dhall_parser/src/dhall.abnf @@ -384,15 +384,20 @@ path-component = "/" ( 1*path-character / %x22 1*quoted-path-character %x22 ) path = 1*path-component local-raw = - ".." path ; Relative path - / "." path ; Relative path - / "~" path ; Home-anchored path + parent-path + / here-path + / home-path ; NOTE: Backtrack if parsing this alternative fails ; ; This is because the first character of this alternative will be "/", but ; if the second character is "/" or "\" then this should have been parsed ; as an operator instead of a path - / path ; Absolute path + / absolute-path + +parent-path = ".." path ; Relative path +here-path = "." path ; Relative path +home-path = "~" path ; Home-anchored path +absolute-path = path ; Absolute path ; `http[s]` URI grammar based on RFC7230 and RFC 3986 with some differences ; noted below diff --git a/dhall_parser/src/dhall.pest.visibility b/dhall_parser/src/dhall.pest.visibility index 08171b3..f9c9d0b 100644 --- a/dhall_parser/src/dhall.pest.visibility +++ b/dhall_parser/src/dhall.pest.visibility @@ -92,7 +92,7 @@ identifier # quoted_path_character # path_component path -local_raw +# local_raw scheme http_raw authority -- cgit v1.2.3