Skip to content

Commit 1ddcebc

Browse files
committed
Nix.Builtins: replaceStrings: m refactor: optimize; document
1 parent e85758f commit 1ddcebc

File tree

1 file changed

+31
-18
lines changed

1 file changed

+31
-18
lines changed

src/Nix/Builtins.hs

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -949,59 +949,72 @@ replaceStrings tfrom tto ts =
949949

950950
let
951951
-- 2021-02-18: NOTE: if there is no match - the process does not changes the context, simply slides along the string.
952-
-- So it should be more effective to pass the context as the first argument.
952+
-- So it isbe more effective to pass the context as the first argument.
953953
-- And moreover, the `passOneCharNgo` passively passes the context, to context can be removed from it and inherited directly.
954954
-- Then the solution would've been elegant, but the Nix bug prevents elegant implementation.
955-
go input output ctx =
955+
go ctx input output =
956956
case maybePrefixMatch of
957957
Nothing ->
958-
-- Pass the chars until match
959-
passOneCharNgo input output ctx
958+
-- Passively pass the chars
959+
realPassOneChar
960+
960961
Just (matched, replacementNS, unprocessedInput) ->
961962
sendReplaceToOutput
962963

963964
where
964-
sendReplaceToOutput = withNixBug unprocessedInput updatedOutput updatedCtx
965-
withNixBug =
965+
sendReplaceToOutput = sendReplaceToOutputWithNixBug unprocessedInput updatedOutput
966+
sendReplaceToOutputWithNixBug =
966967
bool
967-
go
968-
969968
-- Allowing match on "" is a inherited bug of Nix,
970969
-- when "" is checked - it always matches. And so - when it checks - it always insers a replacement, and then process simply passesthrough the char that was under match.
971970
--
972971
-- repl> builtins.replaceStrings ["" "e"] [" " "i"] "Hello world"
973972
-- " H e l l o w o r l d "
974973
-- repl> builtins.replaceStrings ["ll" ""] [" " "i"] "Hello world"
975974
-- "iHie ioi iwioirilidi"
976-
passOneCharNgo
977-
(matched == mempty)
975+
(go updatedCtx) -- true tail recursion
976+
bugPassOneChar -- augmented recursion
977+
isNixBugCase
978+
979+
isNixBugCase = matched == mempty
978980

979981
updatedOutput = output <> replacement
980982
replacement = Builder.fromText $ stringIgnoreContext replacementNS
981983

982984
updatedCtx = ctx <> replacementCtx
983985
replacementCtx = NixString.getContext replacementNS
984986

987+
-- The bug modifies the content, so need to pass modified args => bug demands `pass` to be a real function =>
988+
-- `go` calls `pass` function
989+
-- `pass` calls `go` function
990+
-- In other words, bug creates a case of mutual recusion.
991+
bugPassOneChar input output =
992+
maybe
993+
(finish updatedCtx output) -- The base case - there is no chars left to process -> finish
994+
(\(c, i) -> go updatedCtx i (output <> Builder.singleton c)) -- If there are chars - pass one char & continue
995+
(Text.uncons input) -- chip first char
985996
where
986997
-- When prefix matched something - returns (match, replacement, reminder)
987998
maybePrefixMatch :: Maybe (Text, NixString, Text)
988999
maybePrefixMatch = formMatchReplaceTailInfo <$> find ((`Text.isPrefixOf` input) . fst) fromKeysToValsMap
1000+
where
1001+
formMatchReplaceTailInfo = (\(m, r) -> (m, r, Text.drop (Text.length m) input))
9891002

990-
formMatchReplaceTailInfo = (\(m, r) -> (m, r, Text.drop (Text.length m) input))
1003+
fromKeysToValsMap = zip (fmap stringIgnoreContext fromKeys) toVals
9911004

992-
fromKeysToValsMap = zip (fmap stringIgnoreContext fromKeys) toVals
993-
994-
passOneCharNgo input output =
1005+
-- Not passing args => It is constant that gets embedded into `go` => It is simple `go` tail recursion
1006+
realPassOneChar =
9951007
maybe
996-
(finish output) -- The base case - there is no chars left to process -> finish
997-
(\(c, t) -> go t (output <> Builder.singleton c)) -- If there are chars - pass one char & continue
1008+
(finish ctx output) -- The base case - there is no chars left to process -> finish
1009+
(\(c, i) -> go ctx i (output <> Builder.singleton c)) -- If there are chars - pass one char & continue
9981010
(Text.uncons input) -- chip first char
9991011

1012+
10001013
-- 2021-02-18: NOTE: rly?: toStrict . toLazyText
10011014
-- Maybe `text-builder`, `text-show`?
1002-
finish = makeNixString . LazyText.toStrict . Builder.toLazyText
1015+
finish ctx output = makeNixString (LazyText.toStrict $ Builder.toLazyText output) ctx
10031016

1004-
toValue $ go (stringIgnoreContext string) mempty $ NixString.getContext string
1017+
toValue $ go (NixString.getContext string) (stringIgnoreContext string) mempty
10051018

10061019
removeAttrs
10071020
:: forall e t f m

0 commit comments

Comments
 (0)