28529845fb73d2323f98cbc9f37745332dd959d9
[mes.git] / build-aux / mes-snarf.scm
1 #! /bin/sh
2 # -*- scheme -*-
3 exec ${GUILE-guile} --no-auto-compile -L $HOME/src/mes/build-aux -L build-aux -e '(@@ (mes-snarf) main)' -s "$0" ${1+"$@"}
4 !#
5
6 ;;; Mes --- Maxwell Equations of Software
7 ;;; Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
8 ;;;
9 ;;; mes-snarf.scm: This file is part of Mes.
10 ;;;
11 ;;; Mes is free software; you can redistribute it and/or modify it
12 ;;; under the terms of the GNU General Public License as published by
13 ;;; the Free Software Foundation; either version 3 of the License, or (at
14 ;;; your option) any later version.
15 ;;;
16 ;;; Mes is distributed in the hope that it will be useful, but
17 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;;; GNU General Public License for more details.
20 ;;;
21 ;;; You should have received a copy of the GNU General Public License
22 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
23
24 (define-module (mes-snarf)
25   #:use-module (srfi srfi-1)
26   #:use-module (srfi srfi-26)
27   #:use-module (ice-9 curried-definitions)
28   #:use-module (ice-9 rdelim)
29   #:use-module (ice-9 regex)
30   #:use-module (oop goops))
31
32 (define ((regexp-replace regexp replace) string)
33   (or (and=> (string-match regexp string)
34              (cut regexp-substitute #f <> 'pre replace 'post))
35       string))
36
37 (define GCC? #f)
38 ;; (define-record-type function (make-function name formals annotation)
39 ;;   function?
40 ;;   (name .name)
41 ;;   (formals .formals)
42 ;;   (annotation .annotation))
43
44 (define-class <file> ()
45   (name #:accessor .name #:init-keyword #:name)
46   (content #:accessor .content #:init-keyword #:content))
47
48 (define-class <function> ()
49   (name #:accessor .name #:init-keyword #:name)
50   (formals #:accessor .formals #:init-keyword #:formals)
51   (annotation #:accessor .annotation #:init-keyword #:annotation))
52
53 (define (function-scm-name f)
54   (or (assoc-ref (.annotation f) 'name)
55       (let ((name ((compose
56                     (regexp-replace "_" "-")
57                     (regexp-replace "_" "-")
58                     (regexp-replace "_" "-")
59                     (regexp-replace "_" "-")
60                     (regexp-replace "^builtin_" "")
61                     (regexp-replace "_to_" "->")
62                     (regexp-replace "_x$" "!")
63                     (regexp-replace "_p$" "?"))
64                    (.name f))))
65         (if (not (string-suffix? "-" name)) name
66             (string-append "core:" (string-drop-right name 1))))))
67
68 (define %builtin-prefix% "scm_")
69 (define (function-builtin-name f)
70   (string-append %builtin-prefix% (.name f)))
71
72 (define %cell-prefix% "cell_")
73 (define (function-cell-name f)
74   (string-append %cell-prefix% (.name f)))
75
76 (define %start 1)
77 (define (symbol->header s i)
78   (format #f "#define cell_~a ~a\n" s i))
79
80 (define (symbol->source s i)
81   (string-append
82    (format #f "g_free++;\n")
83    (format #f "g_cells[cell_~a] = scm_~a;\n\n" s s)))
84
85 (define (symbol->names s i)
86   (string-append
87    (format #f "g_cells[cell_~a].car = cstring_to_list (scm_~a.name);\n" s s)))
88
89 (define (function->header f i)
90   (let* ((arity (or (assoc-ref (.annotation f) 'arity)
91                     (if (string-null? (.formals f)) 0
92                         (length (string-split (.formals f) #\,)))))
93          (n (if (eq? arity 'n) -1 arity)))
94     (string-append
95      (format #f "SCM ~a (~a);\n" (.name f) (.formals f))
96      (if GCC?
97          (format #f "function_t fun_~a = {.function~a=&~a, .arity=~a};\n" (.name f) arity (.name f) n)
98          (format #f "function_t fun_~a = {&~a, ~a};\n" (.name f) (.name f) n))
99      (if GCC?
100          (format #f "scm ~a = {FUNCTION, .name=~S, .function=0};\n" (function-builtin-name f) (function-scm-name f))
101          (format #f "scm ~a = {FUNCTION, ~S, 0};\n" (function-builtin-name f) (function-scm-name f)))
102      (format #f "SCM cell_~a;\n\n" (.name f)))))
103
104 (define (function->source f i)
105   (string-append
106    (format #f "~a.function = g_function;\n" (function-builtin-name f))
107    (format #f "functions[g_function++] = fun_~a;\n" (.name f))
108    (format #f "cell_~a = g_free++;\n" (.name f))
109    (format #f "g_cells[cell_~a] = ~a;\n\n" (.name f) (function-builtin-name f))))
110
111 (define (function->environment f i)
112   (string-append
113    (format #f "scm_~a.string = cstring_to_list (scm_~a.name);\n" (.name f) (.name f))
114    (format #f "g_cells[cell_~a].string = MAKE_STRING (scm_~a.string);\n" (.name f) (.name f))
115    (format #f "a = acons (make_symbol (scm_~a.string), ~a, a);\n\n" (.name f) (function-cell-name f))))
116
117 (define (snarf-symbols string)
118   (let* ((matches (list-matches "\nscm scm_([a-z_0-9]+) = [{](SPECIAL|SYMBOL)," string)))
119     (map (cut match:substring <> 1) matches)))
120
121 (define (snarf-functions string)
122   (let* ((matches (list-matches
123                    "\nSCM[ \n]?([a-z0-9_]+) [(]((SCM ?[^,)]+|, )*)[)][^\n(]*([^\n]*)"
124                    string)))
125     (map (lambda (m)
126            (make <function>
127              #:name (match:substring m 1)
128              #:formals (match:substring m 2)
129              #:annotation (with-input-from-string (match:substring m 4) read)))
130          matches)))
131
132 (define (content? f)
133   ((compose not string-null? .content) f))
134
135 (define (internal? f)
136   ((compose (cut assoc-ref <> 'internal) .annotation) f))
137
138 (define (no-environment? f)
139   ((compose (cut assoc-ref <> 'no-environment) .annotation) f))
140
141 (define (generate-includes file-name)
142   (let* ((string (with-input-from-file file-name read-string))
143          (functions (snarf-functions string))
144          (functions (delete-duplicates functions (lambda (a b) (equal? (.name a) (.name b)))))
145          (functions (filter (negate internal?) functions))
146          (symbols (snarf-symbols string))
147          (base-name (basename file-name ".c"))
148          (header (make <file>
149                    #:name (string-append base-name ".h")
150                    #:content (string-join (map function->header functions (iota (length functions) (+ %start (length symbols)))) "")))
151          (source (make <file>
152                         #:name (string-append base-name ".i")
153                         #:content (string-join (map function->source (filter (negate no-environment?) functions) (iota (length functions) (+ (length symbols) %start))) ""))) 
154          (environment (make <file>
155                         #:name (string-append base-name ".environment.i")
156                         #:content (string-join (map function->environment (filter (negate no-environment?) functions) (iota (length functions) (+ (length symbols) %start))) "")))
157          (symbols.h (make <file>
158                       #:name (string-append base-name ".symbols.h")
159                       #:content (string-join (map symbol->header symbols (iota (length symbols) %start)) "")))
160          (symbols.i (make <file>
161                       #:name (string-append base-name ".symbols.i")
162                       #:content (string-join (map symbol->source symbols (iota (length symbols))) "")))
163          (symbol-names.i (make <file>
164                           #:name (string-append base-name ".symbol-names.i")
165                           #:content (string-join (map symbol->names symbols (iota (length symbols))) ""))))
166     (list header source environment symbols.h symbols.i symbol-names.i)))
167
168 (define (file-write file)
169   (with-output-to-file (.name file) (lambda () (display (.content file)))))
170
171 (define (main args)
172   (let* ((files (cdr args)))
173     (map file-write (filter content? (append-map generate-includes files)))))
174
175 ;;(define string (with-input-from-file "../mes.c" read-string))