Foo
[0/4]
(defun generate-match-expression (op arity &optional (type '=))
(declare (symbol op type)
(integer arity))
(ecase type
(=
`(and (eq function ',op)
(= arg-count ,arity)))
(>
`(and (eq function ',op)
(> arg-count ,arity)))
(>=
`(and (eq function ',op)
(>= arg-count ,arity)))))
(defmacro defrule (name (on arity &optional type) (&rest arguments) &body rule)
(let ((match-expression (generate-match-expression on arity type))
(test-name (symbolicate name '-test))
(expansion-name (symbolicate name '-expansion)))
`(progn
(defun ,test-name (function &rest arguments &aux (arg-count (length arguments)))
,match-expression)
(defun ,expansion-name (,@arguments)
,@rule)
(setf (aget *rules* ',name)
(make-rule :name ',name
:test-function #',test-name
:expansion-function #',expansion-name))
',name)))
(defstruct (rule (:type list))
name test-function expansion-function)
(defvar *rules* '())
(defun get-expansion (expression)
(rule-expansion-function (rest
(first
(remove-if-not #'(lambda (nte)
(let ((test (rule-test-function (rest nte))))
(apply test expression)))
,*rules*)))))
[0/10]
(defrule multiplication (* 2 >=) (&rest elements)
(format nil "{~{{~a}~^ \\cdot ~}}"
(map 'list #'convert-to-tex
(map 'list #'ensure-list
elements))))
(defrule division (/ 2 =) (a b)
(format nil "{\\frac{~a}{~a}}"
(convert-to-tex (ensure-list a))
(convert-to-tex (ensure-list b))))
(defrule addition (+ 2 >=) (&rest elements)
(format nil "{~{{~a}~^ + ~}}"
(map 'list #'convert-to-tex
(map 'list #'ensure-list
elements))))
(defrule subtraction (- 2 >=) (&rest elements)
(format nil "{~{{~a}~^ - ~}}"
(map 'list #'convert-to-tex
(map 'list #'ensure-list
elements))))
(defrule exp (exp 1 =) (expression)
(format nil "{e^{~a}}"
(convert-to-tex (ensure-list expression))))
(defrule expt (expt 2 =) (base exponent)
(format nil "{~a ^ {~a}}"
(convert-to-tex (ensure-list base))
(convert-to-tex (ensure-list exponent))))
(defrule natlog (log 1 =) (expression)
(format nil "{\\ln {~a}}"
(convert-to-tex (ensure-list expression))))
(defrule logarithm (log 2 =) (expression base)
(format nil "{\\log_{~a}~a}"
(convert-to-tex (ensure-list base))
(convert-to-tex (ensure-list expression))))
(defrule sin (sin 1 =) (arg)
(format nil "{\\sin {~a}}"
(convert-to-tex (ensure-list arg))))
(defrule cos (cos 1 =) (arg)
(format nil "{\\cos {~a}}"
(convert-to-tex (ensure-list arg))))
(defrule tan (tan 1 =) (arg)
(format nil "{\\tan {~a}}"
(convert-to-tex (ensure-list arg))))
(defrule csc (csc 1 =) (arg)
(format nil "{\\csc {~a}}"
(convert-to-tex (ensure-list arg))))
(defrule sec (sec 1 =) (arg)
(format nil "{\\sec {~a}}"
(convert-to-tex (ensure-list arg))))
(defrule cot (cot 1 =) (arg)
(format nil "{\\cot {~a}}"
(convert-to-tex (ensure-list arg))))
(defrule and (and 2 >=) (&rest elements)
(format nil "{~{{~a}~^ \\wedge ~}}"
(map 'list #'convert-to-tex
(map 'list #'ensure-list elements))))
(defrule or (or 2 >=) (&rest elements)
(format nil "{~{{~a}~^ \\vee ~}}"
(map 'list #'convert-to-tex
(map 'list #'ensure-list elements))))
(defrule not (not 1 =) (&rest elements)
(format nil "{\\not {~a}}"
(map 'list #'convert-to-tex
(map 'list #'ensure-list elements))))
(defrule = (= 2 =) (lhs rhs)
(format nil "{{~a} = {~a}}"
(convert-to-tex (ensure-list lhs))
(convert-to-tex (ensure-list rhs))))
(defrule sum (sum 3 =) (start stop expression)
(format nil "{\\sum_{~a}^{~a} {~a}}"
(convert-to-tex (ensure-list start))
(convert-to-tex (ensure-list stop))
(convert-to-tex (ensure-list expression))))
(defrule integrate (integrate 4 =) (from to expression wrt)
(format nil "{\\int_{~a}^{~a} ~a\\,\mathrm{d}~a}"
(convert-to-tex (ensure-list from))
(convert-to-tex (ensure-list to))
(convert-to-tex (ensure-list expression))
(convert-to-tex (ensure-list wrt))))
(defrule parens (parens 2 =) (type inside)
(let* ((types '((square . ("[" . "]"))
(curly . ("{" . "}"))
(smooth . ("(" . ")"))))
(left (cadr (assoc type types)))
(right (cddr (assoc type types))))
(format nil "{\\left~a {~a} \\right~a}"
left
(convert-to-tex (ensure-list inside))
right)))
(defvar *tex-outputp* nil)
(declaim (special *tex-outputp*))
(defmacro with-tex-output (&body body)
`(if *tex-outputp*
(progn
,@body)
(let ((*tex-outputp* t))
(format nil "$~a$"
(progn
,@body)))))
(defun convert-to-tex (function)
(check-type function cons)
(let ((op (first function)))
(with-tex-output
(cond
((numberp op)
(format nil "~a" op))
((and (symbolp op)
(= 1 (length function)))
(let ((symbol-pair (assoc op *special-symbols-to-sequences*)))
(if (null symbol-pair)
(string-downcase op)
(cdr symbol-pair))))
(t
(let ((expansion-function (get-expansion function)))
(if (functionp expansion-function)
(apply expansion-function (rest function))
(error "Undefined expansion for operation: ~a." op))))))))
(defun ensure-list (list)
(if (listp list)
list
(list list)))
(defvar *special-symbols-to-sequences*
'((alpha . "\\alpha")
(beta . "\\beta")
(gamma . "\\gamma")
(delta . "\\delta")
(epsilon . "\\epsilon")
(varepsilon . "\\varepsilon")
(zeta . "\\zeta")
(eta . "\\eta")
(theta . "\\theta")
(vartheta . "\\vartheta")
(gamma . "\\gamma") (kappa . "\\kappa")
(lambda . "\\lambda")
(mu . "\\mu")
(nu . "\\nu")
(xi . "\\xi")
(omicron . "\\o")
(pi . "\\pi")
(varpi . "\\varpi")
(rho . "\\rho")
(varrho . "\\varrho")
(sigma . "\\sigma")
(varsigm . "\\varsigm")
(tau . "\\tau")
(upsilon . "\\upsilon")
(phi . "\\phi")
(varphi . "\\varphi")
(chi . "\\chi")
(psi . "\\psi")
(omega . "\\omega")
(big-gamma . "\\Gamma")
(big-delta . "\\Delta")
(big-theta . "\\Theta")
(big-lambda . "\\Lambda")
(big-xi . "\\Xi")
(big-pi . "\\Pi")
(big-sigma . "\\Sigma")
(big-upsilon . "\\Upsilon")
(big-phi . "\\Phi")
(big-psi . "\\Psi")
(big-omega . "\\Omega")))
;;;; to-tex.lisp
;;;;
;;;; Copyright (c) 2015 Samuel W. Flint <swflint@flintfam.org>
(defpackage #:to-tex
(:use #:cl
#:com.informatimago.common-lisp.cesarum.list)
(:import-from #:alexandria
#:symbolicate)
(:export #:convert-to-tex))
(in-package #:to-tex)
;;; "to-tex" goes here.
<<misc-functions>>
<<rule-storage>>
<<gen-match-test>>
<<def-match-rule>>
<<retrieve-rule>>
<<conversion-driver>>
<<addition-rule>>
<<subtraction-rule>>
<<multiplication-rule>>
<<division-rule>>
<<exponentials-and-logarithms>>
<<trigonometrics>>
<<logic-rules>>
<<equality-rules>>
<<summation-and-integration>>
<<specialty>>
;;; End to-tex