diff options
author | Basile Henry | 2020-10-25 18:30:57 +0100 |
---|---|---|
committer | GitHub | 2020-10-25 18:30:57 +0100 |
commit | 8f15b9a53f85ec1f806a36c5d1a0fe455e077e70 (patch) | |
tree | 32d311e0aff29e77b167c95a0051d916b2788c4c /dhall | |
parent | 49e202de4478c2933f9179ea23efc7d991c35381 (diff) | |
parent | 0f2522aadcc81481b14c8611db2777670a85ab32 (diff) |
Merge pull request #181 from basile-henry/text-replace
Implement Text/replace
Diffstat (limited to 'dhall')
-rw-r--r-- | dhall/src/builtins.rs | 51 | ||||
-rw-r--r-- | dhall/src/syntax/text/dhall.abnf | 2 | ||||
-rw-r--r-- | dhall/tests/parser/success/builtinsB.txt | 2 | ||||
-rw-r--r-- | dhall/tests/spec.rs | 11 |
4 files changed, 62 insertions, 4 deletions
diff --git a/dhall/src/builtins.rs b/dhall/src/builtins.rs index 16d656f..e80bf6b 100644 --- a/dhall/src/builtins.rs +++ b/dhall/src/builtins.rs @@ -3,7 +3,8 @@ use std::convert::TryInto; use crate::operations::{BinOp, OpKind}; use crate::semantics::{ - skip_resolve_expr, typecheck, Hir, HirKind, Nir, NirKind, NzEnv, VarEnv, + nze, skip_resolve_expr, typecheck, Hir, HirKind, Nir, NirKind, NzEnv, + VarEnv, }; use crate::syntax::Const::Type; use crate::syntax::{ @@ -43,6 +44,7 @@ pub enum Builtin { ListIndexed, ListReverse, TextShow, + TextReplace, } impl Builtin { @@ -78,6 +80,7 @@ impl Builtin { "List/indexed" => Some(ListIndexed), "List/reverse" => Some(ListReverse), "Text/show" => Some(TextShow), + "Text/replace" => Some(TextReplace), _ => None, } } @@ -211,7 +214,12 @@ pub fn type_of_builtin(b: Builtin) -> Hir { DoubleShow => make_type!(Double -> Text), TextShow => make_type!(Text -> Text), - + TextReplace => make_type!( + forall (needle: Text) -> + forall (replacement: Text) -> + forall (haystack: Text) -> + Text + ), ListBuild => make_type!( forall (a: Type) -> (forall (list: Type) -> @@ -401,6 +409,44 @@ fn apply_builtin(b: Builtin, args: Vec<Nir>, env: NzEnv) -> NirKind { } _ => Ret::DoneAsIs, }, + (Builtin::TextReplace, [needle, replacement, haystack]) => { + // Helper to match a Nir as a text literal + fn nir_to_string(n: &Nir) -> Option<String> { + match &*n.kind() { + TextLit(n_lit) => n_lit.as_text(), + _ => None, + } + } + + // The needle and the haystack need to be fully + // evaluated as Text otherwise no progress can be made + match (nir_to_string(needle), nir_to_string(haystack)) { + (Some(n), Some(h)) => { + // When the needle is empty the haystack is returned untouched + if n.is_empty() { + Ret::Nir(haystack.clone()) + // Fast case when replacement is fully evaluated + } else if let Some(r) = nir_to_string(replacement) { + Ret::Nir(Nir::from_text(h.replace(&n, &r))) + } else { + use itertools::Itertools; + + let parts = h.split(&n).map(|s| { + InterpolatedTextContents::Text(s.to_string()) + }); + let replacement = + InterpolatedTextContents::Expr(replacement.clone()); + + Ret::Nir(Nir::from_kind(NirKind::TextLit( + nze::nir::TextLit::new( + parts.intersperse(replacement), + ), + ))) + } + } + _ => Ret::DoneAsIs, + } + } (Builtin::ListLength, [_, l]) => match &*l.kind() { EmptyListLit(_) => Ret::NirKind(Num(Natural(0))), NEListLit(xs) => Ret::NirKind(Num(Natural(xs.len()))), @@ -560,6 +606,7 @@ impl std::fmt::Display for Builtin { ListIndexed => "List/indexed", ListReverse => "List/reverse", TextShow => "Text/show", + TextReplace => "Text/replace", }) } } diff --git a/dhall/src/syntax/text/dhall.abnf b/dhall/src/syntax/text/dhall.abnf index 2d487f5..e913341 100644 --- a/dhall/src/syntax/text/dhall.abnf +++ b/dhall/src/syntax/text/dhall.abnf @@ -412,6 +412,7 @@ builtin = / List-indexed
/ List-reverse
/ Text-show
+ / Text-replace
/ Bool
/ True
/ False
@@ -464,6 +465,7 @@ List-last = %x4c.69.73.74.2f.6c.61.73.74 List-indexed = %x4c.69.73.74.2f.69.6e.64.65.78.65.64
List-reverse = %x4c.69.73.74.2f.72.65.76.65.72.73.65
Text-show = %x54.65.78.74.2f.73.68.6f.77
+Text-replace = %x54.65.78.74.2f.72.65.70.6c.61.63.65
; Operators
combine = %x2227 / "/\"
diff --git a/dhall/tests/parser/success/builtinsB.txt b/dhall/tests/parser/success/builtinsB.txt index 1005949..3d3e292 100644 --- a/dhall/tests/parser/success/builtinsB.txt +++ b/dhall/tests/parser/success/builtinsB.txt @@ -1 +1 @@ -[Natural/fold, Natural/build, Natural/isZero, Natural/even, Natural/odd, Natural/toInteger, Natural/show, Integer/toDouble, Integer/show, Integer/negate, Integer/clamp, Natural/subtract, Double/show, List/build, List/fold, List/length, List/head, List/last, List/indexed, List/reverse, Text/show, Bool, True, False, Optional, None, Natural, Integer, Double, Text, List, Type, Kind, Sort] +[Natural/fold, Natural/build, Natural/isZero, Natural/even, Natural/odd, Natural/toInteger, Natural/show, Integer/toDouble, Integer/show, Integer/negate, Integer/clamp, Natural/subtract, Double/show, List/build, List/fold, List/length, List/head, List/last, List/indexed, List/reverse, Text/show, Text/replace, Bool, True, False, Optional, None, Natural, Integer, Double, Text, List, Type, Kind, Sort] diff --git a/dhall/tests/spec.rs b/dhall/tests/spec.rs index 9572d52..8d67892 100644 --- a/dhall/tests/spec.rs +++ b/dhall/tests/spec.rs @@ -519,6 +519,10 @@ fn define_features() -> Vec<TestFeature> { || path == "simple/integerToDouble" // TODO: fix Double/show || path == "prelude/JSON/number/1" + // With builtin not implemented yet + || path == "unit/WithCreateIntermediateRecords" + || path == "unit/WithDesugar" + || path == "unit/WithPartiallyAbstract" }), ..default_feature.clone() }, @@ -538,7 +542,12 @@ fn define_features() -> Vec<TestFeature> { variant: SpecTestKind::TypeInferenceSuccess, // TODO: this fails because of caching shenanigans // too_slow_path: Rc::new(|path: &str| path == "prelude"), - exclude_path: Rc::new(|path: &str| path == "prelude"), + exclude_path: Rc::new(|path: &str| { + false + || path == "prelude" + // With builtin not implemented yet + || path == "unit/WithCreateIntermediateRecords" + }), ..default_feature.clone() }, TestFeature { |