Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nix
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: b01d62285cdc
Choose a base ref
...
head repository: NixOS/nix
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f134fc4cbecc
Choose a head ref
  • 2 commits
  • 3 files changed
  • 1 contributor

Commits on May 17, 2017

  1. Copy the full SHA
    e46090e View commit details
  2. Copy the full SHA
    f134fc4 View commit details
Showing with 36 additions and 20 deletions.
  1. +10 −4 doc/manual/expressions/builtins.xml
  2. +23 −16 src/libexpr/primops.cc
  3. +3 −0 tests/lang/eval-okay-regex-match.nix
14 changes: 10 additions & 4 deletions doc/manual/expressions/builtins.xml
Original file line number Diff line number Diff line change
@@ -213,10 +213,11 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
<varlistentry><term><function>builtins.match</function>
<replaceable>regex</replaceable> <replaceable>str</replaceable></term>

<listitem><para>Returns a list if
<replaceable>regex</replaceable> matches
<replaceable>str</replaceable> precisely, otherwise returns <literal>null</literal>.
Each item in the list is a regex group.
<listitem><para>Returns a list if the <link
xlink:href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04">extended
POSIX regular expression</link> <replaceable>regex</replaceable>
matches <replaceable>str</replaceable> precisely, otherwise returns
<literal>null</literal>. Each item in the list is a regex group.

<programlisting>
builtins.match "ab" "abc"
@@ -236,6 +237,11 @@ builtins.match "a(b)(c)" "abc"

Evaluates to <literal>[ "b" "c" ]</literal>.

<programlisting>
builtins.match "[[:space:]]+([[:upper:]]+)[[:space:]]+" " FOO "
</programlisting>

Evaluates to <literal>[ "foo" ]</literal>.

</para></listitem>
</varlistentry>
39 changes: 23 additions & 16 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
@@ -1709,26 +1709,33 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
‘null’ or a list containing substring matches. */
static void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
std::regex regex(state.forceStringNoCtx(*args[0], pos), std::regex::extended);
auto re = state.forceStringNoCtx(*args[0], pos);

PathSet context;
const std::string str = state.forceString(*args[1], context, pos);
try {

std::regex regex(re, std::regex::extended);

std::smatch match;
if (!std::regex_match(str, match, regex)) {
mkNull(v);
return;
}
PathSet context;
const std::string str = state.forceString(*args[1], context, pos);

// the first match is the whole string
const size_t len = match.size() - 1;
state.mkList(v, len);
for (size_t i = 0; i < len; ++i) {
if (!match[i+1].matched)
mkNull(*(v.listElems()[i] = state.allocValue()));
else
mkString(*(v.listElems()[i] = state.allocValue()), match[i + 1].str().c_str());
std::smatch match;
if (!std::regex_match(str, match, regex)) {
mkNull(v);
return;
}

// the first match is the whole string
const size_t len = match.size() - 1;
state.mkList(v, len);
for (size_t i = 0; i < len; ++i) {
if (!match[i+1].matched)
mkNull(*(v.listElems()[i] = state.allocValue()));
else
mkString(*(v.listElems()[i] = state.allocValue()), match[i + 1].str().c_str());
}

} catch (std::regex_error &) {
throw EvalError("invalid regular expression ‘%s’, at %s", re, pos);
}
}

3 changes: 3 additions & 0 deletions tests/lang/eval-okay-regex-match.nix
Original file line number Diff line number Diff line change
@@ -17,8 +17,11 @@ assert matches "fo+" "foo";
assert matches "fo{1,2}" "foo";
assert !matches "fo{1,2}" "fooo";
assert !matches "fo*" "foobar";
assert matches "[[:space:]]+([^[:space:]]+)[[:space:]]+" " foo ";
assert !matches "[[:space:]]+([[:upper:]]+)[[:space:]]+" " foo ";

assert match "(.*)\\.nix" "foobar.nix" == [ "foobar" ];
assert match "[[:space:]]+([[:upper:]]+)[[:space:]]+" " FOO " == [ "FOO" ];

assert splitFN "/path/to/foobar.nix" == [ "/path/to/" "/path/to" "foobar" "nix" ];
assert splitFN "foobar.cc" == [ null null "foobar" "cc" ];