1(defpackage org.lispbuilds.nix/nix
2 (:documentation "Utilities for generating Nix code")
3 (:use :cl)
4 (:import-from :str)
5 (:import-from :ppcre)
6 (:import-from :arrow-macros :->>)
7 (:import-from :org.lispbuilds.nix/util :replace-regexes)
8 (:export
9 :nix-eval
10 :nixify-symbol
11 :system-master
12 :make-pname
13 :*nix-attrs-depth*))
14
15(in-package org.lispbuilds.nix/nix)
16
17;; Path names are alphanumeric and can include the symbols +-._?= and
18;; must not begin with a period.
19(defun make-pname (string)
20 (replace-regexes '("^[.]" "[^a-zA-Z0-9+-._?=]")
21 '("_" "_")
22 string))
23
24(defun system-master (system)
25 (first (str:split "/" system)))
26
27;;;; Nix generation
28
29(defun nix-eval (exp)
30 (assert (consp exp))
31 (ecase (car exp)
32 (:string (nix-string (cadr exp)))
33 (:list (apply #'nix-list (rest exp)))
34 (:funcall (apply #'nix-funcall (rest exp)))
35 (:attrs (nix-attrs (cdr exp)))
36 (:merge (apply #'nix-merge (cdr exp)))
37 (:symbol (nix-symbol (cadr exp)))))
38
39(defun nix-string (object)
40 (format nil "\"~a\"" object))
41
42(defun nixify-symbol (string)
43 (flet ((fix-special-chars (str)
44 (replace-regexes '("[_]" "[+]$" "[+][/]" "[+]" "[.]" "[/]")
45 '("__" "_plus" "_plus/" "_plus_" "_dot_" "_slash_")
46 str)))
47 (if (ppcre:scan "^[0-9]" string)
48 (str:concat "_" (fix-special-chars string))
49 (fix-special-chars string))))
50
51
52(defun nix-symbol (object)
53 (nixify-symbol (format nil "~a" object)))
54
55(defun nix-list (&rest things)
56 (format nil "[ ~{~A~^ ~} ]" (mapcar 'nix-eval things)))
57(defvar *nix-attrs-depth* 0)
58
59(defun nix-attrs (keyvals)
60 (when (null keyvals)
61 (return-from nix-attrs "{}"))
62 (let ((*nix-attrs-depth* (1+ *nix-attrs-depth*)))
63 (format
64 nil
65 (->> "{~%*depth*~{~{~A = ~A;~}~^~%*depth*~}~%*depth-1*}"
66 (str:replace-all "*depth*" (str:repeat *nix-attrs-depth* " "))
67 (str:replace-all "*depth-1*" (str:repeat (1- *nix-attrs-depth*) " ")))
68 (mapcar (lambda (keyval)
69 (let ((key (car keyval))
70 (val (cadr keyval)))
71 (list (nix-symbol key)
72 (nix-eval val))))
73 keyvals))))
74
75(defun nix-funcall (fun &rest args)
76 (format nil "(~a ~{~a~^ ~})"
77 (nixify-symbol fun)
78 (mapcar 'nix-eval args)))
79
80(defun nix-merge (a b)
81 (format nil "(~a // ~b)"
82 (nix-eval a)
83 (nix-eval b)))