1 | ;; |
---|
2 | ;; NEMO |
---|
3 | ;; |
---|
4 | ;; Copyright 2008 Ivan Raikov. |
---|
5 | ;; |
---|
6 | ;; This program is free software: you can redistribute it and/or |
---|
7 | ;; modify it under the terms of the GNU General Public License as |
---|
8 | ;; published by the Free Software Foundation, either version 3 of the |
---|
9 | ;; License, or (at your option) any later version. |
---|
10 | ;; |
---|
11 | ;; This program is distributed in the hope that it will be useful, but |
---|
12 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
14 | ;; General Public License for more details. |
---|
15 | ;; |
---|
16 | ;; A full copy of the GPL license can be found at |
---|
17 | ;; <http://www.gnu.org/licenses/>. |
---|
18 | ;; |
---|
19 | |
---|
20 | |
---|
21 | (require-extension srfi-1) |
---|
22 | (require-extension syntax-case) |
---|
23 | (require-extension matchable) |
---|
24 | (require-extension args) |
---|
25 | (require-extension nemo-macros) |
---|
26 | (require-extension nemo-nmodl) |
---|
27 | (require-extension nemo-hh) |
---|
28 | |
---|
29 | |
---|
30 | (define (lookup-def k lst . rest) |
---|
31 | (let-optionals rest ((default #f)) |
---|
32 | (let ((kv (assoc k lst))) |
---|
33 | (if (not kv) default |
---|
34 | (match kv ((k v) v) (else (cdr kv))))))) |
---|
35 | |
---|
36 | (define ($ x) (and x (string->symbol (->string x)))) |
---|
37 | |
---|
38 | ;;; Procedures for string concatenation and pretty-printing |
---|
39 | |
---|
40 | (define (s+ . lst) (string-concatenate (map ->string lst))) |
---|
41 | (define (sw+ lst) (string-intersperse (filter-map (lambda (x) (and x (->string x))) lst) " ")) |
---|
42 | (define (s\ p . lst) (string-intersperse (map ->string lst) p)) |
---|
43 | (define (sl\ p lst) (string-intersperse (map ->string lst) p)) |
---|
44 | (define nl "\n") |
---|
45 | |
---|
46 | ;;; Error/warning procedures for the XML parser |
---|
47 | |
---|
48 | (define (parser-error port message . specialising-msgs) |
---|
49 | (error (string-append message (string-concatenate (map ->string specialising-msgs))))) |
---|
50 | |
---|
51 | (define (ssax:warn port message . specialising-msgs) |
---|
52 | (print-error-message message (current-output-port) "Warning") |
---|
53 | (print (string-concatenate (map ->string specialising-msgs)))) |
---|
54 | |
---|
55 | (define opts |
---|
56 | `( |
---|
57 | ,(args:make-option (i) (required: "FORMAT") |
---|
58 | (s+ "specify input format (xml, sxml, s-exp)") |
---|
59 | (string->symbol arg)) |
---|
60 | ,(args:make-option (xml) (optional: "FILE") |
---|
61 | (s+ "write XML output to file (default: <model-name>.xml)")) |
---|
62 | ,(args:make-option (sxml) (optional: "FILE") |
---|
63 | (s+ "write SXML output to file (default: <model-name>.sxml)")) |
---|
64 | ,(args:make-option (nmodl) (optional: "FILE") |
---|
65 | (s+ "write NMODL output to file (default: <model-name>.mod)")) |
---|
66 | ,(args:make-option (nmodl-method) (required: "METHOD") |
---|
67 | (s+ "specify NMODL integration method (cnexp, derivimplicit)") |
---|
68 | (string->symbol arg)) |
---|
69 | ,(args:make-option (t) #:none |
---|
70 | (s+ "use interpolation tables in generated code") |
---|
71 | #t) |
---|
72 | ,(args:make-option (h help) #:none "Print help" |
---|
73 | (usage)) |
---|
74 | |
---|
75 | )) |
---|
76 | |
---|
77 | |
---|
78 | ;; Use args:usage to generate a formatted list of options (from OPTS), |
---|
79 | ;; suitable for embedding into help text. |
---|
80 | (define (usage) |
---|
81 | (print "Usage: " (car (argv)) " [options...] <list of files to be processed> ") |
---|
82 | (newline) |
---|
83 | (print "The following options are recognized: ") |
---|
84 | (newline) |
---|
85 | (print (parameterize ((args:indent 5) (args:width 30)) (args:usage opts))) |
---|
86 | (exit 1)) |
---|
87 | |
---|
88 | |
---|
89 | ;; Process arguments and collate options and arguments into OPTIONS |
---|
90 | ;; alist, and operands (filenames) into OPERANDS. |
---|
91 | (define args (command-line-arguments)) |
---|
92 | (set!-values (options operands) (args:parse args opts)) |
---|
93 | |
---|
94 | |
---|
95 | (define (ncml:sxpath query doc) |
---|
96 | ((sxpath query '((ncml . "ncml"))) doc)) |
---|
97 | |
---|
98 | (define (ncml:car-sxpath query doc) |
---|
99 | (let ((lst ((sxpath query '((ncml . "ncml") )) doc))) |
---|
100 | (car lst))) |
---|
101 | |
---|
102 | (define (ncml:if-car-sxpath query doc) |
---|
103 | (let ((lst ((sxpath query '((ncml . "ncml") )) doc))) |
---|
104 | (and (not (null? lst)) (car lst)))) |
---|
105 | |
---|
106 | (define (ncml:if-sxpath query doc) |
---|
107 | (let ((lst ((sxpath query '((ncml . "ncml") )) doc))) |
---|
108 | (and (not (null? lst)) lst))) |
---|
109 | |
---|
110 | (define (ncml-binding->binding node) |
---|
111 | (match node |
---|
112 | (('ncml:bnd ('@ ('id id)) ('ncml:expr expr)) |
---|
113 | `(,($ id) ,(ncml-expr->expr expr))) |
---|
114 | (else (error 'ncml-binding->binding "invalid binding " node)))) |
---|
115 | |
---|
116 | (define (ncml-expr->expr node) |
---|
117 | (match node |
---|
118 | ((? number?) node) |
---|
119 | ((? string?) (sxml:number node)) |
---|
120 | (('ncml:id id) (string->symbol (->string id))) |
---|
121 | (('ncml:apply ('@ ('id id)) . args) (cons ($ id) (map ncml-expr->expr args))) |
---|
122 | (('ncml:let ('ncml:bnds . bnds) ('ncml:expr body)) |
---|
123 | `(let ,(map ncml-binding->binding bnds) ,(ncml-expr->expr body))) |
---|
124 | (((and op (? symbol?)) . args) |
---|
125 | (cons (ncml-op->op op) (map ncml-expr->expr args))) |
---|
126 | (else (error 'ncml-expr->expr "unknown expression " node)))) |
---|
127 | |
---|
128 | |
---|
129 | (define (ncml-op->op op) |
---|
130 | (case op |
---|
131 | ((ncml:sum) '+) |
---|
132 | ((ncml:sub) '-) |
---|
133 | ((ncml:mul) '*) |
---|
134 | ((ncml:div) '/) |
---|
135 | ((ncml:gt) '>) |
---|
136 | ((ncml:lt) '<) |
---|
137 | ((ncml:lte) '<=) |
---|
138 | ((ncml:gte) '>=) |
---|
139 | ((ncml:eq) '=) |
---|
140 | (else (match (string-split (->string op) ":") |
---|
141 | ((pre op) (string->symbol op)) |
---|
142 | (else (error 'ncml-op->op "invalid operator" op)))))) |
---|
143 | |
---|
144 | |
---|
145 | (define (nemo-constructor name declarations) |
---|
146 | (let* ((nemo (make-nemo-core)) |
---|
147 | (sys ((nemo 'system) name))) |
---|
148 | (eval-nemo-system-decls nemo name sys declarations) |
---|
149 | (list sys nemo))) |
---|
150 | |
---|
151 | (define (sexp->model options doc) |
---|
152 | (match doc |
---|
153 | (('nemo-model model-name model-decls) |
---|
154 | (let* ((model+nemo (nemo-constructor model-name model-decls)) |
---|
155 | (model (first model+nemo)) |
---|
156 | (nemo (second model+nemo))) |
---|
157 | (let ((model-1 (nemo:hh-transformer model))) |
---|
158 | (if (assoc 'depgraph options) (print "dependency graph: " ((nemo 'depgraph*) model-1))) |
---|
159 | (if (assoc 'exports options) (print "exports: " ((nemo 'exports) model-1))) |
---|
160 | (if (assoc 'imports options) (print "imports: " ((nemo 'imports) model-1))) |
---|
161 | (if (assoc 'components options) |
---|
162 | (for-each (lambda (x) |
---|
163 | (print "component " x ": " ((nemo 'component-exports) model-1 (second x))) |
---|
164 | (print "component " x " subcomponents: " ((nemo 'component-subcomps) model-1 (second x)))) |
---|
165 | ((nemo 'components) model-1))) |
---|
166 | model-1))) |
---|
167 | (else (error 'sexp->model "unknown model format")))) |
---|
168 | |
---|
169 | (define (model->nmodl options model) |
---|
170 | (nemo:nmodl-translator model (lookup-def 'method options) (lookup-def 'table options) -150 150 1)) |
---|
171 | |
---|
172 | |
---|
173 | (define (transition->ncml-transition x) |
---|
174 | (match x (('-> src dst rate) |
---|
175 | `(ncml:transition (@ (src ,src) (dst ,dst)) |
---|
176 | (ncml:rate ,(expr->ncml-expr rate)))) |
---|
177 | (else (error 'transition->ncml-transition "invalid transition " x)))) |
---|
178 | |
---|
179 | (define builtin-fns |
---|
180 | `(+ - * / pow neg abs atan asin acos sin cos exp ln |
---|
181 | sqrt tan cosh sinh tanh hypot gamma lgamma log10 log2 log1p ldexp cube |
---|
182 | > < <= >= = and or round ceiling floor max min)) |
---|
183 | |
---|
184 | (define (binding->ncml-binding bnd) |
---|
185 | (match bnd |
---|
186 | ((id expr) `(ncml:bnd (@ (id ,id)) (ncml:expr ,(expr->ncml-expr expr)))) |
---|
187 | (else (error 'binding->ncml-binding "invalid binding " bnd)))) |
---|
188 | |
---|
189 | (define (expr->ncml-expr x) |
---|
190 | (match x |
---|
191 | ((? number?) x) |
---|
192 | ((? symbol?) `(ncml:id ,x)) |
---|
193 | (('let bnds expr) |
---|
194 | `(ncml:let (ncml:bnds . ,(map binding->ncml-binding bnds)) |
---|
195 | (ncml:expr ,(expr->ncml-expr expr)))) |
---|
196 | (((and op (? symbol?)) . args) |
---|
197 | (let ((ncml-expr (if (member op builtin-fns) |
---|
198 | (cons (op->ncml-op op) (map expr->ncml-expr args)) |
---|
199 | `(ncml:apply (@ (id ,op)) ,@(map expr->ncml-expr args))))) |
---|
200 | ncml-expr)) |
---|
201 | (else (error 'expr->ncml-expr "unknown expression " x)))) |
---|
202 | |
---|
203 | |
---|
204 | |
---|
205 | (define (op->ncml-op op) |
---|
206 | (case op |
---|
207 | ((+) 'ncml:sum) |
---|
208 | ((-) 'ncml:sub) |
---|
209 | ((*) 'ncml:mul) |
---|
210 | ((/) 'ncml:div) |
---|
211 | ((>) 'ncml:gt) |
---|
212 | ((<) 'ncml:lt) |
---|
213 | ((<=) 'ncml:lte) |
---|
214 | ((>=) 'ncml:gte) |
---|
215 | ((=) 'ncml:eq) |
---|
216 | (else (string->symbol (string-append "ncml:" (->string op)))))) |
---|
217 | |
---|
218 | |
---|
219 | (define (make-component->ncml dis model) |
---|
220 | (lambda (x) |
---|
221 | (let ((en (environment-ref model x))) |
---|
222 | (cond ((procedure? en) |
---|
223 | (let ((fd (procedure-data en))) |
---|
224 | `(ncml:defun (@ (id ,x)) |
---|
225 | ,@(map (lambda (v) `(ncml:arg ,v)) (lookup-def 'vars fd)) |
---|
226 | (ncml:body ,(expr->ncml-expr (lookup-def 'body fd)))))) |
---|
227 | (else |
---|
228 | (match en |
---|
229 | |
---|
230 | (($ nemo:quantity 'EXTERNAL local-name name namespace) |
---|
231 | (if namespace |
---|
232 | `(ncml:input (@ (id ,name)) (as ,local-name) (from ,namespace)) |
---|
233 | `(ncml:input (@ (id ,name)) (as ,local-name)))) |
---|
234 | (($ nemo:quantity 'CONST name value) |
---|
235 | `(ncml:const (@ (id ,name)) (ncml:expr ,value))) |
---|
236 | |
---|
237 | (($ nemo:quantity 'ASGN name value rhs) |
---|
238 | (let ((expr (expr->ncml-expr rhs))) |
---|
239 | `(ncml:asgn (@ (id ,name)) (ncml:expr ,expr)))) |
---|
240 | |
---|
241 | (($ nemo:quantity 'TSCOMP name initial open trs p) |
---|
242 | (let ((sxml-trs (map transition->ncml-transition trs))) |
---|
243 | `(ncml:state_complex (@ (id ,name)) |
---|
244 | (ncml:open ,open) (ncml:initial ,(expr->ncml-expr initial)) |
---|
245 | (ncml:transitions ,@sxml-trs) |
---|
246 | (ncml:power ,(expr->ncml-expr p))))) |
---|
247 | |
---|
248 | (($ nemo:quantity 'COMPONENT name type lst) |
---|
249 | (let ((component->ncml (make-component->ncml dis model)) |
---|
250 | (component-exports ((dis 'component-exports) model x))) |
---|
251 | (case type |
---|
252 | ((toplevel) `(,@(map component->ncml lst) |
---|
253 | ,@(map (lambda (x) `(ncml:output (@ (id ,x)))) component-exports))) |
---|
254 | (else `(ncml:component (@ (name ,name) (type ,type)) |
---|
255 | ,@(filter-map component->ncml lst) |
---|
256 | ,@(map (lambda (x) `(ncml:output (@ (id ,x)))) component-exports) |
---|
257 | ))))) |
---|
258 | |
---|
259 | (else #f))))))) |
---|
260 | |
---|
261 | |
---|
262 | (define (model->ncml options model) |
---|
263 | (match-let ((($ nemo:quantity 'DISPATCH dis) (environment-ref model (nemo-intern 'dispatch)))) |
---|
264 | (let ((sysname ((dis 'sysname) model)) |
---|
265 | (component->ncml (make-component->ncml dis model))) |
---|
266 | `(ncml:model (@ (name ,sysname)) ,@(component->ncml (nemo-intern 'toplevel)))))) |
---|
267 | |
---|
268 | |
---|
269 | (require-extension stx-engine) |
---|
270 | (require-extension sxpath-plus) |
---|
271 | (require-extension sxml-transforms) |
---|
272 | (require-extension sxml-tools) |
---|
273 | |
---|
274 | (include "SXML.scm") |
---|
275 | (include "SSAX.scm") |
---|
276 | (include "SXML-to-XML.scm") |
---|
277 | |
---|
278 | |
---|
279 | (define null-template `(*default* ,(lambda (node bindings root env) '()))) |
---|
280 | |
---|
281 | (define-syntax sxml:make-null-ss |
---|
282 | (syntax-rules () |
---|
283 | ((stx rule ...) |
---|
284 | (list |
---|
285 | ; default handler |
---|
286 | null-template |
---|
287 | ; handler for textual nodes |
---|
288 | (list '*text* (lambda (text) text)) |
---|
289 | rule ...)))) |
---|
290 | |
---|
291 | (define (ensure-xmlns doc) |
---|
292 | (sxml:add-attr doc '(xmlns ncml))) |
---|
293 | |
---|
294 | |
---|
295 | ;; based on SRV:send-reply by Oleg Kiselyov |
---|
296 | (define (print-fragments b) |
---|
297 | (let loop ((fragments b) (result #f)) |
---|
298 | (cond |
---|
299 | ((null? fragments) result) |
---|
300 | ((not (car fragments)) (loop (cdr fragments) result)) |
---|
301 | ((null? (car fragments)) (loop (cdr fragments) result)) |
---|
302 | ((eq? #t (car fragments)) (loop (cdr fragments) #t)) |
---|
303 | ((pair? (car fragments)) |
---|
304 | (loop (cdr fragments) (loop (car fragments) result))) |
---|
305 | ((procedure? (car fragments)) |
---|
306 | ((car fragments)) |
---|
307 | (loop (cdr fragments) #t)) |
---|
308 | (else |
---|
309 | (display (car fragments)) |
---|
310 | (loop (cdr fragments) #t))))) |
---|
311 | |
---|
312 | |
---|
313 | (define (ncml->decls ncml:model) |
---|
314 | (letrec |
---|
315 | ((input-template |
---|
316 | (sxml:match 'ncml:input |
---|
317 | (lambda (node bindings root env) |
---|
318 | (let ((id (sxml:attr node 'id)) |
---|
319 | (from (sxml:kidn* 'ncml:from node)) |
---|
320 | (as (sxml:kidn* 'ncml:as node))) |
---|
321 | (if (not id) (error 'input-template "input declaration requires id attribute")) |
---|
322 | (cond ((and from as) `(input (,($ id) as ,($ (second as) ) from ,($ (second from)) ))) |
---|
323 | (from `(input (,($ id) from ,($ (second from))))) |
---|
324 | (as `(input (,($ id) as ,($ (second as))))) |
---|
325 | (else `(input ,($ id)))))))) |
---|
326 | |
---|
327 | (output-template |
---|
328 | (sxml:match 'ncml:output |
---|
329 | (lambda (node bindings root env) |
---|
330 | (let ((id (sxml:attr node 'id))) |
---|
331 | (if (not id) (error 'output-template "output declaration requires id attribute")) |
---|
332 | `(output ,($ id)))))) |
---|
333 | |
---|
334 | (const-template |
---|
335 | (sxml:match 'ncml:const |
---|
336 | (lambda (node bindings root env) |
---|
337 | (let* ((id (sxml:attr node 'id)) |
---|
338 | (expr ((lambda (x) |
---|
339 | (if (not x) |
---|
340 | (error 'const-template "const declaration " id " requires expr element") |
---|
341 | (ncml-expr->expr (second x)))) |
---|
342 | (sxml:kidn* 'ncml:expr node)))) |
---|
343 | (if (not id) (error 'const-template "const declaration requires id attribute")) |
---|
344 | `(const ,($ id) = ,expr))))) |
---|
345 | |
---|
346 | (state-complex-transition-template |
---|
347 | (sxml:match 'ncml:transition |
---|
348 | (lambda (node bindings root env) |
---|
349 | (let ((src (sxml:attr node 'src)) |
---|
350 | (dst (sxml:attr node 'dst)) |
---|
351 | (rate ((lambda (x) |
---|
352 | (if (not x) |
---|
353 | (error 'state-complex-transition-template |
---|
354 | "state complex transition requires rate element") |
---|
355 | (ncml-expr->expr (second x)))) |
---|
356 | (sxml:kidn* 'ncml:rate node)))) |
---|
357 | (if (not src) (error 'state-complex-transition-template |
---|
358 | "state complex transition requires src attribute")) |
---|
359 | (if (not dst) (error 'state-complex-transition-template |
---|
360 | "state complex transition requires dst attribute")) |
---|
361 | |
---|
362 | `(-> ,($ src) ,($ dst) ,rate))))) |
---|
363 | |
---|
364 | (asgn-template |
---|
365 | (sxml:match 'ncml:asgn |
---|
366 | (lambda (node bindings root env) |
---|
367 | (let ((id (sxml:attr node 'id)) |
---|
368 | (expr ((lambda (x) |
---|
369 | (if (not x) |
---|
370 | (error 'asgn-template "algebraic assignment requires expr element") |
---|
371 | (ncml-expr->expr (second x)))) |
---|
372 | (sxml:kidn* 'ncml:expr node)))) |
---|
373 | (if (not id) (error 'asgn-template "algebraic assignment requires id attribute")) |
---|
374 | `(,($ id) = ,expr))))) |
---|
375 | |
---|
376 | |
---|
377 | (state-complex-template |
---|
378 | (sxml:match 'ncml:state_complex |
---|
379 | (lambda (node bindings root env) |
---|
380 | (let ((id (string->symbol (->string (sxml:attr node 'id)))) |
---|
381 | (initial ((lambda (x) |
---|
382 | (if (not x) |
---|
383 | (error 'state-complex-template |
---|
384 | "state complex declaration requires initial element") |
---|
385 | (ncml-expr->expr (second x)))) |
---|
386 | (sxml:kidn* 'ncml:initial node))) |
---|
387 | (open ((lambda (x) |
---|
388 | (if (not x) |
---|
389 | (error 'state-complex-template |
---|
390 | "state complex declaration requires open element") |
---|
391 | ($ (second x)))) |
---|
392 | (sxml:kidn* 'ncml:open node))) |
---|
393 | (power ((lambda (x) |
---|
394 | (if (not x) |
---|
395 | (error 'state-complex-template |
---|
396 | "state complex declaration requires open element") |
---|
397 | (sxml:number (second x)))) |
---|
398 | (sxml:kidn* 'ncml:power node))) |
---|
399 | (transitions ((lambda (x) |
---|
400 | (if (not x) |
---|
401 | (error 'state-complex-template |
---|
402 | "state complex declaration requires transitions element") |
---|
403 | (let ((tmpl (sxml:make-null-ss state-complex-transition-template))) |
---|
404 | (stx:apply-templates (cdr x) tmpl root env)))) |
---|
405 | (sxml:kidn* 'ncml:transitions node)))) |
---|
406 | |
---|
407 | (if (not id) (error 'state-complex-template "state complex transition requires id attribute")) |
---|
408 | `(state-complex (,id (initial ,initial) (open ,open) (power ,power) |
---|
409 | (transitions ,@transitions))))))) |
---|
410 | |
---|
411 | |
---|
412 | (defun-template |
---|
413 | (sxml:match 'ncml:defun |
---|
414 | (lambda (node bindings root env) |
---|
415 | (let ((id (sxml:attr node 'id)) |
---|
416 | (args ((lambda (x) |
---|
417 | (if (null? x) |
---|
418 | (error 'defun-template |
---|
419 | "function definition requires at least one arg element") |
---|
420 | (map (compose $ second) x))) |
---|
421 | (sxml:kidsn 'ncml:arg node))) |
---|
422 | (body ((lambda (x) |
---|
423 | (if (not x) |
---|
424 | (error 'defun-template |
---|
425 | "function definition requires body element") |
---|
426 | (ncml-expr->expr (second x)))) |
---|
427 | (sxml:kidn* 'ncml:body node)))) |
---|
428 | (if (not id) (error 'defun-template "function definition requires id attribute")) |
---|
429 | `(defun ,($ id) ,args ,body))))) |
---|
430 | |
---|
431 | (component-template |
---|
432 | (sxml:match 'ncml:component |
---|
433 | (lambda (node bindings root env) |
---|
434 | (let ((name (sxml:attr node 'name)) |
---|
435 | (type (sxml:attr node 'type))) |
---|
436 | (if (not type) (error 'component-template "component definition requires type attribute")) |
---|
437 | (if name |
---|
438 | `(component (type ,($ type)) (name ,($ name)) ,@(ncml->decls (sxml:kids node))) |
---|
439 | `(component (type ,($ type)) ,@(ncml->decls (sxml:kids node)))))))) |
---|
440 | |
---|
441 | (hh-template |
---|
442 | (sxml:match 'ncml:hh_ionic_conductance |
---|
443 | (lambda (node bindings root env) |
---|
444 | (let* ((or-expr (lambda (x) (and x (ncml-expr->expr (second x))))) |
---|
445 | (id (sxml:attr node 'id)) |
---|
446 | (initial_m (or-expr (sxml:kidn* 'ncml:initial_m node))) |
---|
447 | (initial_h (or-expr (sxml:kidn* 'ncml:initial_h node))) |
---|
448 | (m_power (or-expr (sxml:kidn* 'ncml:m_power node))) |
---|
449 | (h_power (or-expr (sxml:kidn* 'ncml:h_power node))) |
---|
450 | (m_alpha (or-expr (sxml:kidn* 'ncml:m_alpha node))) |
---|
451 | (m_beta (or-expr (sxml:kidn* 'ncml:m_beta node))) |
---|
452 | (h_alpha (or-expr (sxml:kidn* 'ncml:h_alpha node))) |
---|
453 | (h_beta (or-expr (sxml:kidn* 'ncml:h_beta node))) |
---|
454 | (m_tau (or-expr (sxml:kidn* 'ncml:m_tau node))) |
---|
455 | (m_inf (or-expr (sxml:kidn* 'ncml:m_inf node))) |
---|
456 | (h_tau (or-expr (sxml:kidn* 'ncml:h_tau node))) |
---|
457 | (h_inf (or-expr (sxml:kidn* 'ncml:h_inf node)))) |
---|
458 | (if (not id) |
---|
459 | (error 'hh-template "hh ionic conductance definition requires id attribute")) |
---|
460 | `(hh-ionic-conductance |
---|
461 | (,($ id) |
---|
462 | ,@(if initial_m `((initial-m ,initial_m)) `()) |
---|
463 | ,@(if initial_h `((initial-h ,initial_h)) `()) |
---|
464 | ,@(if m_power `((m-power ,m_power)) '()) |
---|
465 | ,@(if h_power `((h-power ,h_power)) '()) |
---|
466 | ,@(if m_alpha `((m-alpha ,m_alpha)) '()) |
---|
467 | ,@(if h_alpha `((h-alpha ,h_alpha)) '()) |
---|
468 | ,@(if m_beta `((m-beta ,m_beta)) '()) |
---|
469 | ,@(if h_beta `((h-beta ,h_beta)) '()) |
---|
470 | ,@(if m_inf `((m-inf ,m_inf)) '()) |
---|
471 | ,@(if h_inf `((h-inf ,h_inf)) '()) |
---|
472 | ,@(if m_tau `((m-tau ,m_tau)) '()) |
---|
473 | ,@(if h_tau `((h-tau ,h_tau)) '()) |
---|
474 | )))))) |
---|
475 | |
---|
476 | ) |
---|
477 | |
---|
478 | (stx:apply-templates ncml:model (sxml:make-null-ss input-template |
---|
479 | output-template |
---|
480 | const-template |
---|
481 | asgn-template |
---|
482 | state-complex-template |
---|
483 | defun-template |
---|
484 | component-template |
---|
485 | hh-template) |
---|
486 | ncml:model (list)))) |
---|
487 | |
---|
488 | |
---|
489 | |
---|
490 | (define (ncml->model options doc) |
---|
491 | (let* ((ncml:model ((lambda (x) |
---|
492 | (if (null? x) (error 'ncml->model "ncml:model element not found in input document") (car x))) |
---|
493 | (ncml:sxpath '(ncml:model) `(*TOP* . ,doc)))) |
---|
494 | (model-name (sxml:attr ncml:model 'name)) |
---|
495 | (model-decls (ncml->decls (sxml:kids ncml:model)))) |
---|
496 | (let* ((model+nemo (nemo-constructor model-name model-decls)) |
---|
497 | (model (first model+nemo)) |
---|
498 | (nemo (second model+nemo))) |
---|
499 | (let ((model-1 (nemo:hh-transformer model))) |
---|
500 | (if (assoc 'depgraph options) (print "dependency graph: " ((nemo 'depgraph*) model-1))) |
---|
501 | (if (assoc 'exports options) (print "exports: " ((nemo 'exports) model-1))) |
---|
502 | (if (assoc 'imports options) (print "imports: " ((nemo 'imports) model-1))) |
---|
503 | (if (assoc 'components options) |
---|
504 | (for-each (lambda (x) |
---|
505 | (print "component " x ": " ((nemo 'component-exports) model-1 (second x))) |
---|
506 | (print "component " x " subcomponents: " ((nemo 'component-subcomps) model-1 (second x)))) |
---|
507 | ((nemo 'components) model-1))) |
---|
508 | model-1)))) |
---|
509 | |
---|
510 | |
---|
511 | |
---|
512 | (define (main options operands) |
---|
513 | (if (null? operands) |
---|
514 | (usage) |
---|
515 | (for-each |
---|
516 | (lambda (operand) |
---|
517 | (let* ((read-xml (lambda (name) (call-with-input-file name |
---|
518 | (lambda (port) (ssax:xml->sxml port '((ncml . "ncml")))) ))) |
---|
519 | (read-sexp (lambda (name) (call-with-input-file name read))) |
---|
520 | (in-format (cond ((lookup-def 'i options) => |
---|
521 | (lambda (x) |
---|
522 | (case ($ x) |
---|
523 | ((s-exp sexp) 'sexp) |
---|
524 | ((sxml) 'sxml) |
---|
525 | ((xml) 'xml) |
---|
526 | (else (error 'nemo "unknown input format" x))))) |
---|
527 | (else (case ((lambda (x) (or (not x) ($ x))) |
---|
528 | (pathname-extension operand)) |
---|
529 | ((s-exp sexp) 'sexp) |
---|
530 | ((sxml) 'sxml) |
---|
531 | ((xml) 'xml) |
---|
532 | (else 'xml))))) |
---|
533 | (doc (case in-format |
---|
534 | ((s-exp sexp) (read-sexp operand)) |
---|
535 | ((sxml) (read-sexp operand)) |
---|
536 | ((xml) (read-xml operand)) |
---|
537 | (else (error 'nemo "unknown input format" in-format)))) |
---|
538 | (model (case in-format |
---|
539 | ((sxml xml) (ncml->model options doc)) |
---|
540 | ((s-exp sexp) (sexp->model options doc)) |
---|
541 | (else (error 'nemo "unknown input format" in-format)))) |
---|
542 | (sxml-fname ((lambda (x) (and x (if (and (cdr x) (string? (cdr x))) |
---|
543 | (s+ (pathname-strip-extension (cdr x)) ".sxml") |
---|
544 | (s+ (pathname-strip-extension operand) ".sxml")))) |
---|
545 | (assoc 'sxml options))) |
---|
546 | (xml-fname ((lambda (x) (and x (if (and (cdr x) (string? (cdr x))) |
---|
547 | (s+ (pathname-strip-extension (cdr x)) ".xml") |
---|
548 | (s+ (pathname-strip-extension operand) ".xml")))) |
---|
549 | (assoc 'xml options))) |
---|
550 | (mod-fname ((lambda (x) (and x (if (and (cdr x) (string? (cdr x))) |
---|
551 | (s+ (pathname-strip-extension (cdr x)) ".mod") |
---|
552 | (s+ (pathname-strip-extension operand) ".mod")))) |
---|
553 | (assoc 'nmodl options))) |
---|
554 | (nmodl-method |
---|
555 | (let ((method ($ (lookup-def 'nmodl-method options) ))) |
---|
556 | (case method |
---|
557 | ((cnexp derivimplicit #f) method) |
---|
558 | (else (error "nmodl-method must be one of cnexp, derivimplicit")))))) |
---|
559 | (if sxml-fname (with-output-to-file sxml-fname (lambda () (pretty-print (model->ncml options model))))) |
---|
560 | (if xml-fname (let* ((doc (model->ncml options model)) |
---|
561 | (doc1 (ensure-xmlns |
---|
562 | (cond ((eq? (car doc) '*TOP*) (assoc 'ncml:model (cdr doc))) |
---|
563 | (else doc))))) |
---|
564 | (with-output-to-file xml-fname (lambda () (print-fragments (generate-XML `(begin ,doc1))))))) |
---|
565 | (if mod-fname |
---|
566 | (with-output-to-file |
---|
567 | mod-fname (lambda () |
---|
568 | (model->nmodl `((method . ,nmodl-method) |
---|
569 | (table . ,(assoc 't options))) model)))) |
---|
570 | )) |
---|
571 | operands))) |
---|
572 | |
---|
573 | (main options operands) |
---|
574 | |
---|