about summary refs log tree commit diff
path: root/users/sterni/nix
diff options
context:
space:
mode:
Diffstat (limited to 'users/sterni/nix')
-rw-r--r--users/sterni/nix/build/buildGopherHole/default.nix109
-rw-r--r--users/sterni/nix/char/tests/default.nix6
-rw-r--r--users/sterni/nix/float/default.nix23
-rw-r--r--users/sterni/nix/float/tests/default.nix49
-rw-r--r--users/sterni/nix/fun/default.nix14
-rw-r--r--users/sterni/nix/html/tests/default.nix2
-rw-r--r--users/sterni/nix/int/default.nix38
-rw-r--r--users/sterni/nix/int/tests/default.nix42
-rw-r--r--users/sterni/nix/list/default.nix30
-rw-r--r--users/sterni/nix/num/default.nix17
-rw-r--r--users/sterni/nix/num/tests/default.nix26
-rw-r--r--users/sterni/nix/string/default.nix1
-rw-r--r--users/sterni/nix/utf8/default.nix27
13 files changed, 310 insertions, 74 deletions
diff --git a/users/sterni/nix/build/buildGopherHole/default.nix b/users/sterni/nix/build/buildGopherHole/default.nix
new file mode 100644
index 0000000000..eec13a8654
--- /dev/null
+++ b/users/sterni/nix/build/buildGopherHole/default.nix
@@ -0,0 +1,109 @@
+{ depot, pkgs, lib, ... }:
+
+let
+  inherit (pkgs)
+    runCommand
+    writeText
+    ;
+
+  inherit (depot.users.sterni.nix.build)
+    buildGopherHole
+    ;
+
+  fileTypes = {
+    # RFC1436
+    text = "0";
+    menu = "1";
+    cso = "2";
+    error = "3";
+    binhex = "4";
+    dos = "5";
+    uuencoded = "6";
+    index-server = "7";
+    telnet = "8";
+    binary = "9";
+    mirror = "+";
+    gif = "g";
+    image = "I";
+    tn3270 = "T";
+    # non-standard
+    info = "i";
+    html = "h";
+  };
+
+  buildFile = { file, name, fileType ? fileTypes.text }:
+    runCommand name
+      {
+        passthru = {
+          # respect the file type the file derivation passes
+          # through. otherwise use explicitly set type or
+          # default value.
+          fileType = file.fileType or fileType;
+        };
+      } ''
+      ln -s ${file} "$out"
+    '';
+
+  buildGopherMap = dir:
+    let
+      /* strings constitute an info line or an empty line
+         if their length is zero. sets that contain a menu
+         value have that added to the gophermap as-is.
+
+         all other entries should be a set which can be built using
+         buildGopherHole and is linked by their name. The resulting
+         derivation is expected to passthru a fileType containing the
+         gopher file type char of themselves.
+      */
+      gopherMapLine = e:
+        if builtins.isString e
+        then e
+        else if e ? menu
+        then e.menu
+        else
+          let
+            drv = buildGopherHole e;
+            title = e.title or e.name;
+          in
+          "${drv.fileType}${title}\t${drv.name}";
+    in
+    writeText ".gophermap" (lib.concatMapStringsSep "\n" gopherMapLine dir);
+
+  buildDir =
+    { dir, name, ... }:
+
+    let
+      # filter all entries out that have to be symlinked:
+      # sets with the file or dir attribute
+      drvOnly = builtins.map buildGopherHole (builtins.filter
+        (x: !(builtins.isString x) && (x ? dir || x ? file))
+        dir);
+      gopherMap = buildGopherMap dir;
+    in
+    runCommand name
+      {
+        passthru = {
+          fileType = fileTypes.dir;
+        };
+      }
+      (''
+        mkdir -p "$out"
+        ln -s "${gopherMap}" "$out/.gophermap"
+      '' + lib.concatMapStrings
+        (drv: ''
+          ln -s "${drv}" "$out/${drv.name}"
+        '')
+        drvOnly);
+in
+
+{
+  # Dispatch into different file / dir handling code
+  # which is mutually recursive with this function.
+  __functor = _: args:
+    if args ? file then buildFile args
+    else if args ? dir then buildDir args
+    else builtins.throw "Unrecognized gopher hole item type: "
+      + lib.generators.toPretty { } args;
+
+  inherit fileTypes;
+}
diff --git a/users/sterni/nix/char/tests/default.nix b/users/sterni/nix/char/tests/default.nix
index 313df47451..cb17b74c57 100644
--- a/users/sterni/nix/char/tests/default.nix
+++ b/users/sterni/nix/char/tests/default.nix
@@ -10,7 +10,7 @@ let
   inherit (depot.users.sterni.nix)
     char
     string
-    int
+    num
     fun
     ;
 
@@ -18,10 +18,10 @@ let
 
   testAllCharConversion = it "tests conversion of all chars" [
     (assertEq "char.chr converts to char.allChars"
-      (builtins.genList (fun.rl char.chr (int.add 1)) 255)
+      (builtins.genList (fun.rl char.chr (num.add 1)) 255)
       charList)
     (assertEq "char.ord converts from char.allChars"
-      (builtins.genList (int.add 1) 255)
+      (builtins.genList (num.add 1) 255)
       (builtins.map char.ord charList))
   ];
 
diff --git a/users/sterni/nix/float/default.nix b/users/sterni/nix/float/default.nix
new file mode 100644
index 0000000000..ecb6465c88
--- /dev/null
+++ b/users/sterni/nix/float/default.nix
@@ -0,0 +1,23 @@
+{ depot, ... }:
+
+let
+  inherit (depot.users.sterni.nix)
+    num
+    ;
+in
+
+rec {
+  # In C++ Nix, the required builtins have been added in version 2.4
+  ceil = builtins.ceil or (throw "Nix implementation is missing builtins.ceil");
+  floor = builtins.floor or (throw "Nix implementation is missing builtins.floor");
+
+  truncate = f: if f >= 0 then floor f else ceil f;
+  round = f:
+    let
+      s = num.sign f;
+      a = s * f;
+    in
+    s * (if a >= floor a + 0.5 then ceil a else floor a);
+
+  intToFloat = i: i * 1.0;
+}
diff --git a/users/sterni/nix/float/tests/default.nix b/users/sterni/nix/float/tests/default.nix
new file mode 100644
index 0000000000..75e2a1bfa0
--- /dev/null
+++ b/users/sterni/nix/float/tests/default.nix
@@ -0,0 +1,49 @@
+{ depot, lib, ... }:
+
+let
+
+  inherit (depot.nix.runTestsuite)
+    runTestsuite
+    it
+    assertEq
+    ;
+
+  inherit (depot.users.sterni.nix)
+    float
+    ;
+
+  testsBuiltins = it "tests builtin operations" [
+    (assertEq "ceil pos" (float.ceil 1.5) 2)
+    (assertEq "ceil neg" (float.ceil (-1.5)) (-1))
+    (assertEq "floor pos" (float.floor 1.5) 1)
+    (assertEq "floor neg" (float.floor (-1.5)) (-2))
+  ];
+
+  testsConversionFrom = it "tests integer to float conversion" [
+    (assertEq "float.intToFloat is identity for floats" (float.intToFloat 1.3) 1.3)
+    (assertEq "float.intToFloat converts ints"
+      (builtins.all
+        (val: builtins.isFloat val)
+        (builtins.map float.intToFloat (builtins.genList (i: i - 500) 1000)))
+      true)
+  ];
+
+  exampleFloats = [ 0.5 0.45 0.3 0.1 200 203.457847 204.65547 (-1.5) (-2) (-1.3) (-0.45) ];
+  testsConversionTo = it "tests float to integer conversion" [
+    (assertEq "round"
+      (builtins.map float.round exampleFloats)
+      [ 1 0 0 0 200 203 205 (-2) (-2) (-1) 0 ])
+    (assertEq "truncate towards zero"
+      (builtins.map float.truncate exampleFloats)
+      [ 0 0 0 0 200 203 204 (-1) (-2) (-1) 0 ])
+  ];
+in
+
+runTestsuite "nix.num" ([
+  testsConversionFrom
+]
+  # Skip for e.g. C++ Nix < 2.4
+++ lib.optionals (builtins ? ceil && builtins ? floor) [
+  testsConversionTo
+  testsBuiltins
+])
diff --git a/users/sterni/nix/fun/default.nix b/users/sterni/nix/fun/default.nix
index bb10f9e6c1..824cebfed2 100644
--- a/users/sterni/nix/fun/default.nix
+++ b/users/sterni/nix/fun/default.nix
@@ -192,20 +192,18 @@ let
             # and the list of arguments to pass to be found in args.
             startSet = [
               {
-                key = "0";
-                id = 0;
+                key = 0;
                 final = false;
                 inherit args;
               }
             ];
 
             operator =
-              { id, final, ... }@state:
+              { key, final, ... }@state:
               let
                 # Plumbing to make genericClosure happy
-                newIds = {
-                  key = toString (id + 1);
-                  id = id + 1;
+                newId = {
+                  key = key + 1;
                 };
 
                 # Perform recursion step
@@ -215,10 +213,10 @@ let
                 # otherwise signal that we're done.
                 newState =
                   if builtins.isAttrs call && call.__tailCall or false
-                  then newIds // {
+                  then newId // {
                     final = false;
                     inherit (call) args;
-                  } else newIds // {
+                  } else newId // {
                     final = true;
                     value = call;
                   };
diff --git a/users/sterni/nix/html/tests/default.nix b/users/sterni/nix/html/tests/default.nix
index 0d80f2f1cd..ed520675c5 100644
--- a/users/sterni/nix/html/tests/default.nix
+++ b/users/sterni/nix/html/tests/default.nix
@@ -75,7 +75,7 @@ let
   ]);
 in
 
-pkgs.runCommandNoCC "html.nix.html"
+pkgs.runCommand "html.nix.html"
 {
   passAsFile = [ "exampleDocument" ];
   inherit exampleDocument;
diff --git a/users/sterni/nix/int/default.nix b/users/sterni/nix/int/default.nix
index 54b5596472..8707445223 100644
--- a/users/sterni/nix/int/default.nix
+++ b/users/sterni/nix/int/default.nix
@@ -2,37 +2,28 @@
 
 let
 
-  # TODO(sterni): implement nix.float and figure out which of these
-  #               functions can be split out into a common nix.num
-  #               library.
-
   inherit (depot.users.sterni.nix)
     string
+    num
     ;
 
   inherit (builtins)
     bitOr
     bitAnd
     bitXor
-    mul
-    div
-    add
-    sub
     ;
 
-  abs = i: if i < 0 then -i else i;
-
   exp = base: pow:
     if pow > 0
     then base * (exp base (pow - 1))
     else if pow < 0
-    then 1.0 / exp base (abs pow)
+    then 1.0 / exp base (num.abs pow)
     else 1;
 
   bitShiftR = bit: count:
     if count == 0
     then bit
-    else div (bitShiftR bit (count - 1)) 2;
+    else (bitShiftR bit (count - 1)) / 2;
 
   bitShiftL = bit: count:
     if count == 0
@@ -52,7 +43,7 @@ let
     in
     if int == 0
     then "0"
-    else "${sign}${go (abs int)}";
+    else "${sign}${go (num.abs int)}";
 
   fromHexMap = builtins.listToAttrs
     (lib.imap0 (i: c: { name = c; value = i; })
@@ -94,26 +85,24 @@ let
   odd = x: bitAnd x 1 == 1;
   even = x: bitAnd x 1 == 0;
 
-  # div and mod behave like quot and rem in Haskell,
-  # i. e. they truncate towards 0
-  mod = a: b: let res = a / b; in a - (res * b);
-
-  inRange = a: b: x: x >= a && x <= b;
+  quot' = builtins.div; # no typecheck
+  rem = a: b:
+    assert builtins.isInt a && builtins.isInt b;
+    let res = quot' a b; in a - (res * b);
+  quot = a: b:
+    assert builtins.isInt a && builtins.isInt b;
+    quot' a b;
 
 in
 {
   inherit
     maxBound
     minBound
-    abs
     exp
     odd
     even
-    add
-    sub
-    mul
-    div
-    mod
+    quot
+    rem
     bitShiftR
     bitShiftL
     bitOr
@@ -121,6 +110,5 @@ in
     bitXor
     toHex
     fromHex
-    inRange
     ;
 }
diff --git a/users/sterni/nix/int/tests/default.nix b/users/sterni/nix/int/tests/default.nix
index 8d2263b421..80bd05b6b5 100644
--- a/users/sterni/nix/int/tests/default.nix
+++ b/users/sterni/nix/int/tests/default.nix
@@ -15,9 +15,6 @@ let
     ;
 
   testBounds = it "checks minBound and maxBound" [
-    # this is gonna blow up in my face because
-    # integer overflow is undefined behavior in
-    # C++, so most likely anything could happen?
     (assertEq "maxBound is the maxBound" true
       (int.maxBound + 1 < int.maxBound))
     (assertEq "minBound is the minBound" true
@@ -321,7 +318,6 @@ let
   testBasic = it "checks basic int operations" [
     (assertEq "122 is even" (int.even 122 && !(int.odd 122)) true)
     (assertEq "123 is odd" (int.odd 123 && !(int.even 123)) true)
-    (assertEq "abs -4959" (int.abs (-4959)) 4959)
   ];
 
   expNumbers = [
@@ -369,12 +365,12 @@ let
   checkShiftRDivExp = n:
     assertEq "${toString n} >> 5 == ${toString n} / 2 ^ 5"
       (int.bitShiftR n 5)
-      (int.div n (int.exp 2 5));
+      (n / (int.exp 2 5));
 
   checkShiftLMulExp = n:
     assertEq "${toString n} >> 6 == ${toString n} * 2 ^ 6"
       (int.bitShiftL n 5)
-      (int.mul n (int.exp 2 5));
+      (n * (int.exp 2 5));
 
   testBit = it "checks bitwise operations" (lib.flatten [
     (builtins.map checkShift shifts)
@@ -410,40 +406,40 @@ let
   ]);
 
   divisions = [
-    { a = 2; b = 1; c = 2; mod = 0; }
-    { a = 2; b = 2; c = 1; mod = 0; }
-    { a = 20; b = 10; c = 2; mod = 0; }
-    { a = 12; b = 5; c = 2; mod = 2; }
-    { a = 23; b = 4; c = 5; mod = 3; }
+    { a = 2; b = 1; c = 2; rem = 0; }
+    { a = 2; b = 2; c = 1; rem = 0; }
+    { a = 20; b = 10; c = 2; rem = 0; }
+    { a = 12; b = 5; c = 2; rem = 2; }
+    { a = 23; b = 4; c = 5; rem = 3; }
   ];
 
-  checkDiv = n: { a, b, c, mod }: [
-    (assertEq "${n}: div result" (int.div a b) c)
-    (assertEq "${n}: mod result" (int.mod a b) mod)
-    (assertEq "${n}: divMod law" ((int.div a b) * b + (int.mod a b)) a)
+  checkQuot = n: { a, b, c, rem }: [
+    (assertEq "${n}: quot result" (int.quot a b) c)
+    (assertEq "${n}: rem result" (int.rem a b) rem)
+    (assertEq "${n}: quotRem law" ((int.quot a b) * b + (int.rem a b)) a)
   ];
 
-  testDivMod = it "checks integer division and modulo"
+  testQuotRem = it "checks integer quotient and remainder"
     (lib.flatten [
-      (builtins.map (checkDiv "+a / +b") divisions)
+      (builtins.map (checkQuot "+a / +b") divisions)
       (builtins.map
-        (fun.rl (checkDiv "-a / +b") (x: x // {
+        (fun.rl (checkQuot "-a / +b") (x: x // {
           a = -x.a;
           c = -x.c;
-          mod = -x.mod;
+          rem = -x.rem;
         }))
         divisions)
       (builtins.map
-        (fun.rl (checkDiv "+a / -b") (x: x // {
+        (fun.rl (checkQuot "+a / -b") (x: x // {
           b = -x.b;
           c = -x.c;
         }))
         divisions)
       (builtins.map
-        (fun.rl (checkDiv "-a / -b") (x: x // {
+        (fun.rl (checkQuot "-a / -b") (x: x // {
           a = -x.a;
           b = -x.b;
-          mod = -x.mod;
+          rem = -x.rem;
         }))
         divisions)
     ]);
@@ -455,5 +451,5 @@ runTestsuite "nix.int" [
   testBasic
   testExp
   testBit
-  testDivMod
+  testQuotRem
 ]
diff --git a/users/sterni/nix/list/default.nix b/users/sterni/nix/list/default.nix
new file mode 100644
index 0000000000..568a76d637
--- /dev/null
+++ b/users/sterni/nix/list/default.nix
@@ -0,0 +1,30 @@
+{ ... }:
+
+{
+  /* For a list of length n that consists of lists of length m,
+     return a list of length m containing lists of length n
+     so that
+
+         builtins.elemAt (builtins.elemAt orig a) b
+         == builtins.elemAt (builtins.elemAt transposed b) a
+
+     Essentially, if you think of the nested list as an array with two
+     dimensions, the two index axes are swapped.
+
+     The length of the inner lists m is determined based on the first element
+     and assumed to be used for all other lists. Malformed input data may
+     cause the function to crash or lose data.
+
+     Type: <n>[ <m>[ ] ] -> <m>[ <n>[ ] ]
+  */
+  transpose = list:
+    let
+      innerLength = builtins.length (builtins.head list);
+      outerLength = builtins.length list;
+    in
+    builtins.genList
+      (inner: builtins.genList
+        (outer: builtins.elemAt (builtins.elemAt list outer) inner)
+        outerLength)
+      innerLength;
+}
diff --git a/users/sterni/nix/num/default.nix b/users/sterni/nix/num/default.nix
new file mode 100644
index 0000000000..81e2f8377f
--- /dev/null
+++ b/users/sterni/nix/num/default.nix
@@ -0,0 +1,17 @@
+{ ... }:
+
+rec {
+  inherit (builtins)
+    mul
+    div
+    add
+    sub
+    ;
+
+  sign = i: if i < 0 then -1 else 1;
+  abs = i: if i < 0 then -i else i;
+
+  inRange = a: b: x: x >= a && x <= b;
+
+  sum = builtins.foldl' (a: b: a + b) 0;
+}
diff --git a/users/sterni/nix/num/tests/default.nix b/users/sterni/nix/num/tests/default.nix
new file mode 100644
index 0000000000..ca5f861deb
--- /dev/null
+++ b/users/sterni/nix/num/tests/default.nix
@@ -0,0 +1,26 @@
+{ depot, ... }:
+
+let
+
+  inherit (depot.nix.runTestsuite)
+    runTestsuite
+    it
+    assertEq
+    ;
+
+  inherit (depot.users.sterni.nix)
+    num
+    ;
+
+  testsBasic = it "tests basic operations" [
+    (assertEq "abs -4959" (num.abs (-4959)) 4959)
+    (assertEq "sum" (num.sum [ 123 321 1.5 ]) (123 + 321 + 1.5))
+    (assertEq "inRange"
+      (builtins.map (num.inRange 1.0 5) [ 0 0.5 3 4 4.5 5.5 5 6 ])
+      [ false false true true true false true false ])
+  ];
+in
+
+runTestsuite "nix.num" [
+  testsBasic
+]
diff --git a/users/sterni/nix/string/default.nix b/users/sterni/nix/string/default.nix
index 852ef2538f..381c8ddff7 100644
--- a/users/sterni/nix/string/default.nix
+++ b/users/sterni/nix/string/default.nix
@@ -87,7 +87,6 @@ let
         ({ out ? "", argIndex ? 0 }: token: {
           argIndex = argIndex + (if specifierWithArg token then 1 else 0);
           out =
-            /**/
             if token == "%s" then out + builtins.elemAt args argIndex
             else if token == "%%" then out + "%"
             else if isSpecifier token then throw "Unsupported format specifier ${token}"
diff --git a/users/sterni/nix/utf8/default.nix b/users/sterni/nix/utf8/default.nix
index 71c846c042..e76695f128 100644
--- a/users/sterni/nix/utf8/default.nix
+++ b/users/sterni/nix/utf8/default.nix
@@ -6,6 +6,7 @@ let
     char
     flow
     fun
+    num
     int
     string
     util
@@ -46,17 +47,17 @@ let
     # byte position as an index starting with 0
     pos:
     let
-      defaultRange = int.inRange 128 191;
+      defaultRange = num.inRange 128 191;
 
       secondBytePredicate = flow.switch first [
-        [ (int.inRange 194 223) defaultRange ] # C2..DF
-        [ 224 (int.inRange 160 191) ] # E0
-        [ (int.inRange 225 236) defaultRange ] # E1..EC
-        [ 237 (int.inRange 128 159) ] # ED
-        [ (int.inRange 238 239) defaultRange ] # EE..EF
-        [ 240 (int.inRange 144 191) ] # F0
-        [ (int.inRange 241 243) defaultRange ] # F1..F3
-        [ 244 (int.inRange 128 143) ] # F4
+        [ (num.inRange 194 223) defaultRange ] # C2..DF
+        [ 224 (num.inRange 160 191) ] # E0
+        [ (num.inRange 225 236) defaultRange ] # E1..EC
+        [ 237 (num.inRange 128 159) ] # ED
+        [ (num.inRange 238 239) defaultRange ] # EE..EF
+        [ 240 (num.inRange 144 191) ] # F0
+        [ (num.inRange 241 243) defaultRange ] # F1..F3
+        [ 244 (num.inRange 128 143) ] # F4
         [ (fun.const true) null ]
       ];
 
@@ -225,10 +226,10 @@ let
       # Note that this doesn't check if the Unicode codepoint is allowed,
       # but rather allows all theoretically UTF-8-encodeable ones.
       count = flow.switch cp [
-        [ (int.inRange 0 127) 1 ] # 00000000 0xxxxxxx
-        [ (int.inRange 128 2047) 2 ] # 00000yyy yyxxxxxx
-        [ (int.inRange 2048 65535) 3 ] # zzzzyyyy yyxxxxxx
-        [ (int.inRange 65536 1114111) 4 ] # 000uuuuu zzzzyyyy yyxxxxxx,
+        [ (num.inRange 0 127) 1 ] # 00000000 0xxxxxxx
+        [ (num.inRange 128 2047) 2 ] # 00000yyy yyxxxxxx
+        [ (num.inRange 2048 65535) 3 ] # zzzzyyyy yyxxxxxx
+        [ (num.inRange 65536 1114111) 4 ] # 000uuuuu zzzzyyyy yyxxxxxx,
         # capped at U+10FFFF
 
         [ (fun.const true) (builtins.throw invalidCodepointMsg) ]