2024-09-04 03:14:57 -07:00
|
|
|
|
;; typeset.lisp -- Typeset proposition tables
|
|
|
|
|
;; Copyright (C) 2024 Alexander Rosenberg
|
|
|
|
|
;;
|
|
|
|
|
;; This program is free software: you can redistribute it and/or modify
|
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
;; (at your option) any later version.
|
|
|
|
|
;;
|
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
;;
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
|
|
|
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
(in-package :truth-table/base)
|
|
|
|
|
|
|
|
|
|
(define-condition table-format-error (error)
|
|
|
|
|
((format :initarg :format
|
|
|
|
|
:accessor table-format-error-format))
|
|
|
|
|
(:report
|
|
|
|
|
(lambda (con stream)
|
|
|
|
|
(format stream "unknown table format: ~a"
|
|
|
|
|
(table-format-error-format con)))))
|
|
|
|
|
|
|
|
|
|
(defparameter *operator-ascii-lookup-alist*
|
|
|
|
|
'((and . "&")
|
|
|
|
|
(nand . "nand")
|
|
|
|
|
(or . "|")
|
|
|
|
|
(nor . "nor")
|
|
|
|
|
(xor . "^")
|
|
|
|
|
(not . "~")
|
|
|
|
|
(implies . "->")
|
|
|
|
|
(converse . "<-")
|
|
|
|
|
(iff . "<->")
|
|
|
|
|
(open-paren . "(")
|
|
|
|
|
(close-paren . ")")
|
|
|
|
|
(true . "T")
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(false . "F")
|
|
|
|
|
(latin-true . "T")
|
|
|
|
|
(latin-false . "F"))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"Lookup table mapping operators to their ASCII representation.")
|
|
|
|
|
|
|
|
|
|
(defparameter *operator-unicode-lookup-alist*
|
|
|
|
|
'((and . "∧")
|
|
|
|
|
(nand . "⊼")
|
|
|
|
|
(or . "∨")
|
|
|
|
|
(nor . "⊽")
|
|
|
|
|
(xor . "⊕")
|
|
|
|
|
(not . "¬")
|
|
|
|
|
(implies . "→")
|
|
|
|
|
(converse . "←")
|
|
|
|
|
(iff . "↔")
|
|
|
|
|
(open-paren . "(")
|
|
|
|
|
(close-paren . ")")
|
|
|
|
|
(true . "⊤")
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(false . "⊥")
|
|
|
|
|
(latin-true . "T")
|
|
|
|
|
(latin-false . "F"))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"Lookup table mapping operators to their Unicode representation.")
|
|
|
|
|
|
|
|
|
|
(defparameter *operator-latex-lookup-alist*
|
|
|
|
|
'((and . "\\land")
|
|
|
|
|
(nand . "\\uparrow")
|
|
|
|
|
(or . "\\lor")
|
|
|
|
|
(nor . "\\downarrow")
|
|
|
|
|
(xor . "\\oplus")
|
|
|
|
|
(not . "\\lnot ")
|
|
|
|
|
(implies . "\\to")
|
|
|
|
|
(converse . "\\gets")
|
|
|
|
|
(iff . "\\leftrightarrow")
|
|
|
|
|
(open-paren . "\\left(")
|
|
|
|
|
(close-paren . "\\right)")
|
|
|
|
|
(true . "\\top")
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(false . "\\bot")
|
|
|
|
|
(latin-true . "\\textrm{T}")
|
|
|
|
|
(latin-false . "\\textrm{F}"))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"Lookup table mapping operators to their LaTeX representation.")
|
|
|
|
|
|
2024-09-05 14:46:05 -07:00
|
|
|
|
(defparameter *operator-html-lookup-alist*
|
|
|
|
|
'((and . "∧")
|
|
|
|
|
(nand . "↑")
|
|
|
|
|
(or . "∨")
|
|
|
|
|
(nor . "↓")
|
|
|
|
|
(xor . "⊕")
|
|
|
|
|
(not . "¬")
|
|
|
|
|
(implies . "→")
|
|
|
|
|
(converse . "←")
|
|
|
|
|
(iff . "↔")
|
|
|
|
|
(open-paren . "(")
|
|
|
|
|
(close-paren . ")")
|
|
|
|
|
(true . "⊤")
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(false . "⊥")
|
|
|
|
|
(latin-true . "T")
|
|
|
|
|
(latin-false . "F"))
|
2024-09-05 14:46:05 -07:00
|
|
|
|
"Lookup table mapping operators to their HTML representation.")
|
|
|
|
|
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(defun latex-var-name-transform (name)
|
|
|
|
|
"Transform NAME so that it is escaped for use in LaTeX."
|
|
|
|
|
(format nil "{~{~A~}}" (loop for char across name
|
|
|
|
|
if (eq char #\\)
|
|
|
|
|
collect "\\backslash "
|
|
|
|
|
else if (eq char #\_)
|
|
|
|
|
collect "\\_"
|
|
|
|
|
else if (eq char #\$)
|
|
|
|
|
collect "\\$"
|
|
|
|
|
else
|
|
|
|
|
collect char)))
|
|
|
|
|
|
2024-09-05 14:46:05 -07:00
|
|
|
|
(defun html-var-name-transform (name)
|
|
|
|
|
"Transform NAME so that it is escaped for use in HTML."
|
|
|
|
|
(format nil "~{~A~}" (loop for char across name
|
|
|
|
|
if (eq char #\<)
|
|
|
|
|
collect "<"
|
|
|
|
|
else if (eq char #\>)
|
|
|
|
|
collect ">"
|
|
|
|
|
else
|
|
|
|
|
collect char)))
|
|
|
|
|
|
2024-09-10 23:05:14 -07:00
|
|
|
|
(defun flattenable-p (oper)
|
|
|
|
|
"Return t if OPER is able to be flattened. That is, it does not care a bout
|
|
|
|
|
argument ordering."
|
|
|
|
|
(multiple-value-bind (min max)
|
|
|
|
|
(operator-argument-count oper)
|
|
|
|
|
(declare (ignorable min))
|
|
|
|
|
;; currently, all unordered operators take any number of arguments max, and
|
|
|
|
|
;; all ordered operators have some max number of arguments (as a
|
|
|
|
|
;; proposition: an operator is unordered if and only if it takes any number
|
|
|
|
|
;; of arguments)
|
|
|
|
|
(not max)))
|
|
|
|
|
|
|
|
|
|
(defun flatten-proposition (prop)
|
|
|
|
|
"Flatten PROP, such that adjacent operators with the same precedence and with
|
|
|
|
|
no ordering (such as \"and\" or \"or\") are not surrounded by parenthesis when
|
|
|
|
|
typeset."
|
|
|
|
|
(if (consp prop)
|
|
|
|
|
(loop with my-oper = (car prop)
|
|
|
|
|
for raw-sub-expr in (cdr prop)
|
|
|
|
|
for sub-expr = (flatten-proposition raw-sub-expr)
|
|
|
|
|
when (and (flattenable-p my-oper)
|
|
|
|
|
(consp sub-expr)
|
|
|
|
|
(eq (car sub-expr) my-oper))
|
|
|
|
|
append (cdr sub-expr) into out-args
|
|
|
|
|
else
|
|
|
|
|
collect sub-expr into out-args
|
|
|
|
|
finally (return (cons my-oper out-args)))
|
|
|
|
|
prop))
|
|
|
|
|
|
2024-09-06 14:58:47 -07:00
|
|
|
|
(defun typeset-proposition (expr &key
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(lookup-table *operator-ascii-lookup-alist*)
|
|
|
|
|
var-name-transform
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(parent-prec most-positive-fixnum)
|
2024-09-10 23:05:14 -07:00
|
|
|
|
latin-truths
|
|
|
|
|
(flatten-prop t))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"Typeset the propositional expression EXPR to plain text. LOOKUP-TABLE should
|
|
|
|
|
be a table mapping operators to their textual representation. VAR-NAME-TRANSFORM
|
|
|
|
|
(if non-nil) should take a single string argument which is a variable name and
|
|
|
|
|
escape it for use in the target typesetting system. PARENT-PERC is for internal
|
|
|
|
|
use (it controls when parentheses are applied.)"
|
|
|
|
|
(cond
|
2024-09-05 14:46:05 -07:00
|
|
|
|
;; expr is empty
|
|
|
|
|
((null expr)
|
|
|
|
|
"")
|
2024-09-04 03:14:57 -07:00
|
|
|
|
;; expr is a variable name
|
|
|
|
|
((stringp expr)
|
|
|
|
|
(if var-name-transform
|
|
|
|
|
(funcall var-name-transform expr)
|
|
|
|
|
expr))
|
|
|
|
|
;; expr is true or false
|
2024-09-10 22:19:43 -07:00
|
|
|
|
((eq expr 'true)
|
|
|
|
|
(if latin-truths
|
|
|
|
|
(cdr (assoc 'latin-true lookup-table))
|
|
|
|
|
(cdr (assoc 'true lookup-table))))
|
|
|
|
|
((eq expr 'false)
|
|
|
|
|
(if latin-truths
|
|
|
|
|
(cdr (assoc 'latin-false lookup-table))
|
|
|
|
|
(cdr (assoc 'false lookup-table))))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
;; expr is a compound expression
|
|
|
|
|
(t
|
2024-09-10 23:05:14 -07:00
|
|
|
|
(destructuring-bind (oper first-arg &rest args)
|
|
|
|
|
(if flatten-prop
|
|
|
|
|
(flatten-proposition expr)
|
|
|
|
|
expr)
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(let* ((our-prec (operator-precedence oper))
|
|
|
|
|
(oper-ascii (cdr (assoc oper lookup-table)))
|
2024-09-10 23:05:14 -07:00
|
|
|
|
(prefix-suffix (if (<= parent-prec our-prec)
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(cons (cdr (assoc 'open-paren lookup-table))
|
|
|
|
|
(cdr (assoc 'close-paren lookup-table)))
|
|
|
|
|
'("" . ""))))
|
|
|
|
|
(if (null args)
|
|
|
|
|
;; we have one argument
|
|
|
|
|
(format nil "~A~A~A~A" (car prefix-suffix) oper-ascii
|
2024-09-06 14:58:47 -07:00
|
|
|
|
(typeset-proposition first-arg
|
|
|
|
|
:lookup-table lookup-table
|
|
|
|
|
:var-name-transform var-name-transform
|
2024-09-10 22:19:43 -07:00
|
|
|
|
:latin-truths latin-truths
|
2024-09-10 23:05:14 -07:00
|
|
|
|
:parent-prec our-prec
|
|
|
|
|
:flatten-prop nil)
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(cdr prefix-suffix))
|
|
|
|
|
;; we have many arguments
|
|
|
|
|
(loop for arg in args
|
|
|
|
|
collect oper-ascii into output
|
|
|
|
|
collect
|
2024-09-06 14:58:47 -07:00
|
|
|
|
(typeset-proposition arg
|
|
|
|
|
:lookup-table lookup-table
|
|
|
|
|
:var-name-transform var-name-transform
|
2024-09-10 22:19:43 -07:00
|
|
|
|
:latin-truths latin-truths
|
2024-09-10 23:05:14 -07:00
|
|
|
|
:parent-prec our-prec
|
|
|
|
|
:flatten-prop nil)
|
2024-09-04 03:14:57 -07:00
|
|
|
|
into output
|
|
|
|
|
finally
|
2024-09-06 14:58:47 -07:00
|
|
|
|
(push (typeset-proposition first-arg
|
|
|
|
|
:lookup-table lookup-table
|
|
|
|
|
:var-name-transform var-name-transform
|
2024-09-10 22:19:43 -07:00
|
|
|
|
:latin-truths latin-truths
|
2024-09-10 23:05:14 -07:00
|
|
|
|
:parent-prec our-prec
|
|
|
|
|
:flatten-prop nil)
|
2024-09-04 03:14:57 -07:00
|
|
|
|
output)
|
|
|
|
|
(return (format nil "~A~{~A~^ ~}~A" (car prefix-suffix)
|
|
|
|
|
output (cdr prefix-suffix))))))))))
|
|
|
|
|
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(defun convert-truth-table-to-latex (table &key pretty-print latin-truths)
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"Convert TABLE, which should be a truth table as returned by
|
2024-09-10 22:19:43 -07:00
|
|
|
|
`create-truth-table' to latex. If PRETTY-PRINT, add newlines to make the
|
|
|
|
|
generated code easier to read.
|
2024-09-04 03:14:57 -07:00
|
|
|
|
NOTE: though the overall order does not matter, the order must be the same
|
|
|
|
|
between each row."
|
|
|
|
|
(let ((typeset-exprs (mapcar (lambda (expr)
|
|
|
|
|
(typeset-proposition
|
2024-09-06 14:58:47 -07:00
|
|
|
|
expr :lookup-table *operator-latex-lookup-alist*
|
2024-09-10 22:19:43 -07:00
|
|
|
|
:var-name-transform 'latex-var-name-transform
|
|
|
|
|
:latin-truths latin-truths))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(extract-truth-table-expressions table))))
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(with-output-to-string (str)
|
|
|
|
|
(format str "~
|
|
|
|
|
\\begin{tabular}{~{~*|c~}|}~@[~% ~*~]~
|
|
|
|
|
\\hline~:[ ~;~% ~]~
|
|
|
|
|
~{$ ~A $~^ & ~} \\\\~:[ ~;~% ~]~
|
|
|
|
|
\\hline~:[ ~;~% ~]"
|
|
|
|
|
typeset-exprs
|
|
|
|
|
pretty-print pretty-print
|
|
|
|
|
typeset-exprs
|
|
|
|
|
pretty-print pretty-print)
|
|
|
|
|
(let ((format-str
|
|
|
|
|
(if latin-truths
|
2024-09-10 23:07:53 -07:00
|
|
|
|
"~{~:[F~;T~]~^ & ~} \\\\~:[ ~;~% ~]"
|
2024-09-10 22:19:43 -07:00
|
|
|
|
"~{$ ~:[\\bot~;\\top~] $~^ & ~} \\\\~:[ ~;~% ~]")))
|
|
|
|
|
(dolist (row (extract-truth-table-values table))
|
|
|
|
|
(format str format-str row pretty-print)))
|
|
|
|
|
(format str "\\hline~@[~%~]\\end{tabular}" pretty-print))))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
|
2024-09-05 14:46:05 -07:00
|
|
|
|
(defun format-html-properties-alist (props)
|
|
|
|
|
"Format PROPS, a list of conses, as a list of HTML properties."
|
|
|
|
|
(loop for (name . value) in props
|
|
|
|
|
when (eq value t)
|
|
|
|
|
collect (format nil "~A=\"\"" name)
|
|
|
|
|
else when value
|
|
|
|
|
collect (format nil "~A=~S" name (princ-to-string value))))
|
|
|
|
|
|
|
|
|
|
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(defun convert-truth-table-to-html (table &key class id more-props
|
|
|
|
|
pretty-print latin-truths)
|
2024-09-05 14:46:05 -07:00
|
|
|
|
"Convert TABLE, which should be a truth table as returned by
|
|
|
|
|
`create-truth-table' to HTML. CLASS and ID are their respective HTML
|
|
|
|
|
properties. MORE-PROPS is an alist mapping properties to values.
|
|
|
|
|
NOTE: though the overall order does not matter, the order must be the same
|
|
|
|
|
between each row."
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(with-output-to-string (str)
|
|
|
|
|
(format str "<table~@[ class=~s~]~@[ id=~s~]~{ ~A~}>~@[~% ~*~]<tr>"
|
2024-09-05 14:46:05 -07:00
|
|
|
|
class id (format-html-properties-alist more-props)
|
2024-09-10 22:19:43 -07:00
|
|
|
|
pretty-print)
|
|
|
|
|
(dolist (expr (extract-truth-table-expressions table))
|
|
|
|
|
(format str "~@[~% ~*~]<th>~a</th>"
|
|
|
|
|
pretty-print
|
|
|
|
|
(typeset-proposition
|
|
|
|
|
expr :lookup-table *operator-html-lookup-alist*
|
2024-09-16 03:25:36 -07:00
|
|
|
|
:var-name-transform 'html-var-name-transform
|
|
|
|
|
:latin-truths latin-truths)))
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(format str "~@[~% ~]</tr>" pretty-print)
|
|
|
|
|
(dolist (row (extract-truth-table-values table))
|
|
|
|
|
(format str "~@[~% ~*~]<tr>~@[~% ~*~]" pretty-print pretty-print)
|
|
|
|
|
(loop with truth-str = (if latin-truths
|
2024-09-16 03:25:36 -07:00
|
|
|
|
"~:[F~;T~]"
|
|
|
|
|
"~:[⊥~;⊤~]")
|
2024-09-10 22:19:43 -07:00
|
|
|
|
for now = row then (cdr now)
|
|
|
|
|
for value = (car now)
|
|
|
|
|
while now do
|
|
|
|
|
(format str "<td>~?</td>" truth-str (list value))
|
|
|
|
|
when (and pretty-print (cdr now)) do
|
|
|
|
|
(format str "~% "))
|
|
|
|
|
(format str "~@[~% ~*~]</tr>" pretty-print))
|
|
|
|
|
(format str "~@[~%~]</table>" pretty-print)))
|
2024-09-05 14:46:05 -07:00
|
|
|
|
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(defparameter *table-border-ascii-alist*
|
|
|
|
|
'((vertical . #\|)
|
|
|
|
|
(horizontal . #\-)
|
|
|
|
|
(right . #\|)
|
|
|
|
|
(left . #\|)
|
|
|
|
|
(up . #\-)
|
|
|
|
|
(down . #\-)
|
|
|
|
|
(cross . #\+)
|
|
|
|
|
(top-left . #\+)
|
|
|
|
|
(top-right . #\+)
|
|
|
|
|
(bottom-left . #\+)
|
|
|
|
|
(bottom-right . #\+))
|
|
|
|
|
"Characters used to draw ASCII table borders.")
|
|
|
|
|
|
|
|
|
|
(defparameter *table-border-unicode-alist*
|
|
|
|
|
'((vertical . #\│)
|
|
|
|
|
(horizontal . #\─)
|
|
|
|
|
(right . #\├)
|
|
|
|
|
(left . #\┤)
|
|
|
|
|
(up . #\┴)
|
|
|
|
|
(down . #\┬)
|
|
|
|
|
(cross . #\┼)
|
|
|
|
|
(top-left . #\┌)
|
|
|
|
|
(top-right . #\┐)
|
|
|
|
|
(bottom-left . #\└)
|
|
|
|
|
(bottom-right . #\┘))
|
|
|
|
|
"Characters used to draw Unicode table borders.")
|
|
|
|
|
|
2024-09-16 02:38:09 -07:00
|
|
|
|
(defun typeset-table-break (stream lengths horiz start column end
|
|
|
|
|
&key (left-pad-len 0) (right-pad-len 0))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"Typeset the first row, the last row, or a break to STREAM. The proper box
|
|
|
|
|
character will be placed at each intersection. LENGTHS is a list of column
|
|
|
|
|
lengths. HORIZ, START, COLUMN, and END are the box characters to use when
|
|
|
|
|
drawing."
|
|
|
|
|
(format stream "~c" start)
|
|
|
|
|
(loop for (length . rest) = lengths then rest
|
|
|
|
|
while length
|
|
|
|
|
do
|
|
|
|
|
(format stream "~a"
|
2024-09-16 02:38:09 -07:00
|
|
|
|
(make-string (+ left-pad-len length right-pad-len)
|
|
|
|
|
:initial-element horiz))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
when rest do
|
|
|
|
|
(format stream "~c" column))
|
|
|
|
|
(format stream "~c" end))
|
|
|
|
|
|
2024-09-16 02:38:09 -07:00
|
|
|
|
(defun typeset-table-row (stream lengths row vert
|
|
|
|
|
&key (align :center) (left-pad-str "")
|
|
|
|
|
(right-pad-str ""))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"Typeset ROW to STREAM. VERT is the vertical separator. LENGTHS should be the
|
|
|
|
|
length of each column."
|
2024-09-16 02:38:09 -07:00
|
|
|
|
(loop with format = (case align
|
|
|
|
|
(:right
|
|
|
|
|
"~c~a~v:<~a~>~a")
|
|
|
|
|
(:left
|
|
|
|
|
"~c~a~v@<~a~>~a")
|
|
|
|
|
(t ;; :center
|
|
|
|
|
"~c~a~v:@<~a~>~a"))
|
|
|
|
|
for col in row
|
2024-09-04 03:14:57 -07:00
|
|
|
|
for length in lengths
|
|
|
|
|
do
|
2024-09-16 02:38:09 -07:00
|
|
|
|
(format stream format
|
|
|
|
|
vert left-pad-str length col right-pad-str))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(format stream "~c" vert))
|
|
|
|
|
|
2024-09-16 02:38:09 -07:00
|
|
|
|
(defmacro with-draw-table ((stream col-widths lookup-table
|
|
|
|
|
&key (padding 0) (align :center))
|
|
|
|
|
&body body)
|
|
|
|
|
"Execute BODY with the function \=:seperator and \=:row bound. STREAM is the
|
|
|
|
|
stream to write the table to. COL-WIDTHS is a list of column
|
|
|
|
|
widths. LOOKUP-TABLE is the table to use to lookup characters for the table
|
|
|
|
|
border. PADDING is the number to spaces to both append and prepend to each table
|
|
|
|
|
cell. ALIGN is one of \=:right, \=:center, or \=:left."
|
|
|
|
|
(let ((pad-str-var (gensym)))
|
|
|
|
|
`(let ((,pad-str-var (make-string ,padding :initial-element #\space)))
|
|
|
|
|
(truth-table/base::typeset-table-break
|
|
|
|
|
,stream ,col-widths
|
|
|
|
|
(cdr (assoc 'horizontal ,lookup-table))
|
|
|
|
|
(cdr (assoc 'top-left ,lookup-table))
|
|
|
|
|
(cdr (assoc 'down ,lookup-table))
|
|
|
|
|
(cdr (assoc 'top-right ,lookup-table))
|
|
|
|
|
:right-pad-len ,padding
|
|
|
|
|
:left-pad-len ,padding)
|
|
|
|
|
(format ,stream "~%")
|
|
|
|
|
(flet ((:seperator ()
|
|
|
|
|
(truth-table/base::typeset-table-break
|
|
|
|
|
,stream ,col-widths
|
|
|
|
|
(cdr (assoc 'horizontal ,lookup-table))
|
|
|
|
|
(cdr (assoc 'right ,lookup-table))
|
|
|
|
|
(cdr (assoc 'cross ,lookup-table))
|
|
|
|
|
(cdr (assoc 'left ,lookup-table))
|
|
|
|
|
:right-pad-len ,padding
|
|
|
|
|
:left-pad-len ,padding)
|
|
|
|
|
(format ,stream "~%"))
|
|
|
|
|
(:row (row)
|
|
|
|
|
(truth-table/base::typeset-table-row
|
|
|
|
|
,stream ,col-widths row
|
|
|
|
|
(cdr (assoc 'vertical ,lookup-table))
|
|
|
|
|
:align ,align
|
|
|
|
|
:left-pad-str ,pad-str-var
|
|
|
|
|
:right-pad-str ,pad-str-var)
|
|
|
|
|
(format ,stream "~%")))
|
|
|
|
|
,@body)
|
|
|
|
|
(truth-table/base::typeset-table-break
|
|
|
|
|
,stream ,col-widths
|
|
|
|
|
(cdr (assoc 'horizontal ,lookup-table))
|
|
|
|
|
(cdr (assoc 'bottom-left ,lookup-table))
|
|
|
|
|
(cdr (assoc 'up ,lookup-table))
|
|
|
|
|
(cdr (assoc 'bottom-right ,lookup-table))
|
|
|
|
|
:right-pad-len ,padding
|
|
|
|
|
:left-pad-len ,padding))))
|
|
|
|
|
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(defun typeset-truth-table (table &optional
|
|
|
|
|
(expr-lookup-table
|
|
|
|
|
*operator-ascii-lookup-alist*)
|
|
|
|
|
(box-lookup-table
|
2024-09-10 22:19:43 -07:00
|
|
|
|
*table-border-ascii-alist*)
|
|
|
|
|
latin-truths)
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"Convert TABLE, which should be a truth table as returned by
|
|
|
|
|
`create-truth-table' to text.
|
|
|
|
|
NOTE: though the overall order does not matter, the order must be the same
|
|
|
|
|
between each row."
|
|
|
|
|
(let* ((typeset-exprs (mapcar (lambda (expr)
|
2024-09-06 14:58:47 -07:00
|
|
|
|
(typeset-proposition
|
2024-09-10 22:19:43 -07:00
|
|
|
|
expr :lookup-table expr-lookup-table
|
2024-09-16 02:38:09 -07:00
|
|
|
|
:latin-truths latin-truths))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(extract-truth-table-expressions table)))
|
2024-09-16 04:23:37 -07:00
|
|
|
|
(col-widths (mapcar 'length typeset-exprs)))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(with-output-to-string (str)
|
2024-09-16 04:23:37 -07:00
|
|
|
|
(with-draw-table (str col-widths box-lookup-table
|
|
|
|
|
:padding 1)
|
2024-09-16 02:38:09 -07:00
|
|
|
|
(:row typeset-exprs)
|
|
|
|
|
(:seperator)
|
|
|
|
|
(dolist (row (extract-truth-table-values table))
|
|
|
|
|
(:row (mapcar
|
|
|
|
|
(lambda (entry)
|
|
|
|
|
(cdr (assoc
|
|
|
|
|
(if entry
|
|
|
|
|
(if latin-truths
|
|
|
|
|
'latin-true
|
|
|
|
|
'true)
|
|
|
|
|
(if latin-truths
|
|
|
|
|
'latin-false
|
|
|
|
|
'false))
|
|
|
|
|
expr-lookup-table)))
|
|
|
|
|
row)))))))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
|
|
|
|
|
(defparameter *known-formats*
|
2024-09-05 14:46:05 -07:00
|
|
|
|
'("unicode" "ascii" "latex" "html")
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"The known formats that `typeset-table-to-format' can take.")
|
|
|
|
|
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(defun typeset-table-to-format (table format
|
|
|
|
|
&key pretty-print latin-truths)
|
2024-09-04 03:14:57 -07:00
|
|
|
|
"Typeset TABLE into FORMAT, or error if FORMAT is not a know format."
|
|
|
|
|
(cond
|
|
|
|
|
((equal format "unicode")
|
|
|
|
|
(typeset-truth-table table *operator-unicode-lookup-alist*
|
2024-09-10 22:19:43 -07:00
|
|
|
|
*table-border-unicode-alist*
|
|
|
|
|
latin-truths))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
((equal format "ascii")
|
|
|
|
|
(typeset-truth-table table *operator-ascii-lookup-alist*
|
2024-09-10 22:19:43 -07:00
|
|
|
|
*table-border-ascii-alist*
|
|
|
|
|
latin-truths))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
((equal format "latex")
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(convert-truth-table-to-latex table
|
|
|
|
|
:pretty-print pretty-print
|
|
|
|
|
:latin-truths latin-truths))
|
2024-09-05 14:46:05 -07:00
|
|
|
|
((equal format "html")
|
2024-09-10 22:19:43 -07:00
|
|
|
|
(convert-truth-table-to-html table
|
|
|
|
|
:pretty-print pretty-print
|
|
|
|
|
:latin-truths latin-truths))
|
2024-09-04 03:14:57 -07:00
|
|
|
|
(t (error 'table-format-error :format format))))
|