New primitives:

* `sub' to subtract two numbers.
* `stringLength' to get the length of a string.
* `substring' to get a substring of a string.  These should be enough
  to allow most string operations to be expressed.
This commit is contained in:
Eelco Dolstra 2007-01-29 14:23:09 +00:00
parent 7dedbd896a
commit 7349bd0176
8 changed files with 88 additions and 6 deletions

View file

@ -55,7 +55,10 @@
<listitem><para>TODO: new built-ins <listitem><para>TODO: new built-ins
<function>builtins.attrNames</function>, <function>builtins.attrNames</function>,
<function>builtins.filterSource</function>.</para></listitem> <function>builtins.filterSource</function>,
<function>builtins.sub</function>,
<function>builtins.stringLength</function>,
<function>builtins.substring</function>.</para></listitem>
</itemizedlist> </itemizedlist>

View file

@ -723,6 +723,14 @@ static Expr primAdd(EvalState & state, const ATermVector & args)
} }
static Expr primSub(EvalState & state, const ATermVector & args)
{
int i1 = evalInt(state, args[0]);
int i2 = evalInt(state, args[1]);
return makeInt(i1 - i2);
}
static Expr primLessThan(EvalState & state, const ATermVector & args) static Expr primLessThan(EvalState & state, const ATermVector & args)
{ {
int i1 = evalInt(state, args[0]); int i1 = evalInt(state, args[0]);
@ -779,6 +787,36 @@ static Expr primFilterSource(EvalState & state, const ATermVector & args)
} }
/*************************************************************
* String manipulation
*************************************************************/
/* `substr start len str' returns the substring of `str' starting at
character position `min(start, stringLength str)' inclusive and
ending at `min(start + len, stringLength str)'. `start' must be
non-negative. */
static Expr prim_substring(EvalState & state, const ATermVector & args)
{
int start = evalInt(state, args[0]);
int len = evalInt(state, args[1]);
PathSet context;
string s = coerceToString(state, args[2], context);
if (start < 0) throw EvalError("negative start position in `substring'");
return makeStr(string(s, start, len), context);
}
static Expr prim_stringLength(EvalState & state, const ATermVector & args)
{
PathSet context;
string s = coerceToString(state, args[0], context);
return makeInt(s.size());
}
void EvalState::addPrimOps() void EvalState::addPrimOps()
{ {
addPrimOp("builtins", 0, primBuiltins); addPrimOp("builtins", 0, primBuiltins);
@ -813,9 +851,13 @@ void EvalState::addPrimOps()
addPrimOp("removeAttrs", 2, primRemoveAttrs); addPrimOp("removeAttrs", 2, primRemoveAttrs);
addPrimOp("relativise", 2, primRelativise); addPrimOp("relativise", 2, primRelativise);
addPrimOp("__add", 2, primAdd); addPrimOp("__add", 2, primAdd);
addPrimOp("__sub", 2, primSub);
addPrimOp("__lessThan", 2, primLessThan); addPrimOp("__lessThan", 2, primLessThan);
addPrimOp("__toFile", 2, primToFile); addPrimOp("__toFile", 2, primToFile);
addPrimOp("__filterSource", 2, primFilterSource); addPrimOp("__filterSource", 2, primFilterSource);
addPrimOp("__substring", 3, prim_substring);
addPrimOp("__stringLength", 1, prim_stringLength);
} }

View file

@ -4,6 +4,9 @@ derivation {
builder = "@shell@"; builder = "@shell@";
args = ["-e" "-x" (builtins.toFile "builder" "PATH=@testPath@; ln -s $input $out")]; args = ["-e" "-x" (builtins.toFile "builder" "PATH=@testPath@; ln -s $input $out")];
input = input =
let filter = path: type: type != "symlink" && baseNameOf (toString path) != "foo"; let filter = path: type:
type != "symlink"
&& baseNameOf path != "foo"
&& !((import ./lang/lib.nix).hasSuffix ".bak" (baseNameOf path));
in builtins.filterSource filter ./test-tmp/filterin; in builtins.filterSource filter ./test-tmp/filterin;
} }

View file

@ -5,6 +5,9 @@ mkdir $TEST_ROOT/filterin
mkdir $TEST_ROOT/filterin/foo mkdir $TEST_ROOT/filterin/foo
touch $TEST_ROOT/filterin/foo/bar touch $TEST_ROOT/filterin/foo/bar
touch $TEST_ROOT/filterin/xyzzy touch $TEST_ROOT/filterin/xyzzy
touch $TEST_ROOT/filterin/b
touch $TEST_ROOT/filterin/bak
touch $TEST_ROOT/filterin/bla.c.bak
ln -s xyzzy $TEST_ROOT/filterin/link ln -s xyzzy $TEST_ROOT/filterin/link
$NIX_BIN_DIR/nix-build ./filter-source.nix -o $TEST_ROOT/filterout $NIX_BIN_DIR/nix-build ./filter-source.nix -o $TEST_ROOT/filterout
@ -12,4 +15,6 @@ $NIX_BIN_DIR/nix-build ./filter-source.nix -o $TEST_ROOT/filterout
set -x set -x
test ! -e $TEST_ROOT/filterout/foo/bar test ! -e $TEST_ROOT/filterout/foo/bar
test -e $TEST_ROOT/filterout/xyzzy test -e $TEST_ROOT/filterout/xyzzy
test -e $TEST_ROOT/filterout/bak
test ! -e $TEST_ROOT/filterout/bla.c.bak
test ! -L $TEST_ROOT/filterout/link test ! -L $TEST_ROOT/filterout/link

View file

@ -0,0 +1 @@
builtins.substring (builtins.sub 0 1) 1 "x"

View file

@ -0,0 +1 @@
Str("ooxfoobarybarzobaabb",[])

View file

@ -0,0 +1,19 @@
with builtins;
let
s = "foobar";
in
substring 1 2 s
+ "x"
+ substring 0 (stringLength s) s
+ "y"
+ substring 3 100 s
+ "z"
+ substring 2 (sub (stringLength s) 3) s
+ "a"
+ substring 3 0 s
+ "b"
+ substring 3 1 s

View file

@ -1,18 +1,26 @@
with builtins;
rec { rec {
fold = op: nul: list: fold = op: nul: list:
if list == [] if list == []
then nul then nul
else op (builtins.head list) (fold op nul (builtins.tail list)); else op (head list) (fold op nul (tail list));
concat = concat =
fold (x: y: x + y) ""; fold (x: y: x + y) "";
flatten = x: flatten = x:
if builtins.isList x if isList x
then fold (x: y: (flatten x) ++ y) [] x then fold (x: y: (flatten x) ++ y) [] x
else [x]; else [x];
sum = fold (x: y: builtins.add x y) 0; sum = fold (x: y: add x y) 0;
hasSuffix = ext: fileName:
let lenFileName = stringLength fileName;
lenExt = stringLength ext;
in !(lessThan lenFileName lenExt) &&
substring (sub lenFileName lenExt) lenFileName fileName == ext;
} }