3 ; Gnumeric Guile plug-in system startup file
5 ; Mark Probst (schani@unix.cslab.tuwien.ac.at)
8 ;(display "Guile plug-in initializing\n")
12 ;; This function is from gnucash, but simplified
13 (define (gnm:error->string tag args)
14 (define (write-error port)
16 (apply display-error (fluid-ref the-last-stack) port args))
19 (call-with-output-string write-error)))
22 (define (make-cell-ref col row)
23 (if (and (number? col) (number? row))
24 (cons 'cell-ref (cons col row))
27 (define (cell-ref? ob)
28 (and (pair? ob) (eq? (car ob) 'cell-ref)))
30 (define cell-ref-col cadr)
32 (define cell-ref-row cddr)
35 (define (make-var cell-ref)
39 (and (pair? ob) (eq? (car ob) 'var)))
41 (define var-cell-ref cdr)
44 (define binary-operator? '())
45 (define binary-operator-name '())
46 (define binary-operator-function '())
47 (let ((binary-op-names
59 (cons 'string-append "&")))
66 (cons '<> (lambda (n1 n2) (not (= n1 n2))))
72 (cons 'string-append string-append))))
74 (set! binary-operator?
76 (if (assq op binary-op-names) #t #f)))
78 (set! binary-operator-name
80 (cdr (assq op binary-op-names))))
82 (set! binary-operator-function
84 (cdr (assq op binary-op-funcs)))))
87 ;; this should really be coded in C
88 (define (unparse-expr expr)
89 (define (unparse-subexpr expr)
91 (number->string expr))
93 (string-append "\"" expr "\"")) ; FIXME: should also quote "'s inside
95 (let ((cell-ref (var-cell-ref expr)))
97 (string (integer->char (+ (char->integer #\A) (cell-ref-col cell-ref)))) ; FIXME: this only works if col < 26
98 (number->string (+ (cell-ref-row cell-ref) 1)))))
100 (let ((op (car expr)))
101 (cond ((binary-operator? op)
103 (unparse-subexpr (cadr expr))
104 (binary-operator-name op)
105 (unparse-subexpr (caddr expr))
108 (string-append "-(" (unparse-subexpr (cadr expr)) ")"))
110 (string-append (cadr expr) "()")) ; FIXME: should unparse args
116 (string-append "=" (unparse-subexpr expr)))
118 ;; this should also be coded in C
119 (define (eval-expr expr)
120 (define (eval-expr-list expr-list)
121 (if (null? expr-list)
123 (cons (eval-expr (car expr-list)) (eval-expr-list (cdr expr-list)))))
125 (cond ((number? expr) expr)
126 ((string? expr) expr)
127 ((var? expr) (cell-value (var-cell-ref expr)))
129 (let ((op (car expr)))
130 (cond ((binary-operator? op)
131 ((binary-operator-function op) (eval-expr (cadr expr)) (eval-expr (caddr expr))))
133 (- (eval-expr (cadr expr))))
135 (gnumeric-funcall (cadr expr) (eval-expr-list (caddr expr))))
143 ; symbolic differentiation with immediate evaluation
144 ;; in case of a funcall this should do numeric differentiation
145 (define (differentiate expr var)
146 (cond ((number? expr) 0)
148 (let ((cell-ref (var-cell-ref expr)))
149 (if (equal? var cell-ref)
151 (differentiate (cell-expr cell-ref) var))))
153 (let ((op (car expr)))
154 (cond ((binary-operator? op)
155 (let ((left-arg (cadr expr))
156 (right-arg (caddr expr)))
158 (+ (differentiate left-arg var) (differentiate right-arg var)))
160 (- (differentiate left-arg var) (differentiate right-arg var)))
162 (+ (* (eval-expr left-arg) (differentiate right-arg var))
163 (* (eval-expr right-arg) (differentiate left-arg var))))
165 (let ((v (eval-expr right-arg)))
166 (/ (- (* (differentiate left-arg var) v)
167 (* (differentiate right-arg var) (eval-expr left-arg)))
170 (let ((u (eval-expr left-arg))
171 (v (eval-expr right-arg))
172 (du (differentiate left-arg var))
173 (dv (differentiate right-arg var)))
174 (+ (* (expt u (- v 1)) v du) (* (expt u v) (log u) dv))))
178 (- (differentiate (cadr expr) var)))
184 ; a little expression simplifier and constant folder
185 (define (simplify-expr expr)
186 (define (constant? expr)
187 (or (number? expr) (string? expr)))
189 (cond ((or (number? expr) (string? expr) (var? expr))
192 (let ((op (car expr)))
193 (cond ((binary-operator? op)
194 (let* ((left-arg (simplify-expr (cadr expr)))
195 (right-arg (simplify-expr (caddr expr)))
196 (new-expr (list op left-arg right-arg)))
197 (cond ((and (constant? left-arg) (constant? right-arg))
198 (eval-expr new-expr))
199 ((and (eq? op '+) (number? left-arg) (zero? left-arg))
201 ((and (or (eq? op '+) (eq? op '-)) (number? right-arg) (zero? right-arg))
203 ((and (eq? op '*) (number? left-arg) (= left-arg 1))
205 ((and (or (eq? op '*) (eq? op '/)) (number? right-arg) (= right-arg 1))
207 ((and (eq? op 'expt) (number? left-arg) (or (zero? left-arg) (= left-arg 1)))
209 ((and (eq? op 'expt) (number? right-arg) (= right-arg 1))
214 (let* ((arg (simplify-expr (cadr expr)))
215 (new-expr (list op arg)))
220 expr)))) ; should also handle functions without side effects
224 ; load user init-file if present
225 (let ((home-gnumericrc (string-append (getenv "HOME") "/.gnumeric/guile.scm")))
226 (if (access? home-gnumericrc R_OK)
227 (load home-gnumericrc)))
229 ;(display "Guile plug-in initialization complete\n")