;;; Copyright (c) 1998--2018 ;;; John Carroll, Ann Copestake, Robert Malouf, Stephan Oepen; ;;; see `LICENSE' for conditions. ;;; ;;; Tools to help build a treebank ;;; ;;; ;;; ToDO ;;; ;;; - at least one-level of `Undo'; ;;; - Shift and Ctrl accelerators on `Next' et al.; ;;; - define equivalence classes of discriminants (possibly based on equality ;;; of in and out sets), so that `yes' selections can propagate; ;;; - group equivalent discriminators somehow; ;;; - add info bar: show numbers of in and out trees per discriminant ;;; - bug fix: identify multiple applications of unary rule at same position; ;;; - investigate lack of edge for leafs in tree in interactive mode; ;;; (in-package :lkb) (def-lkb-parameter *tree-comparison-threshold* 10000) (def-lkb-parameter *tree-display-threshold* 20) (def-lkb-parameter *tree-display-view* :classic) (def-lkb-parameter *tree-display-trees-width* 530) (def-lkb-parameter *tree-display-discriminants-width* 430) (def-lkb-parameter *tree-display-height* 630) ;;; ;;; a switch to control auto-advance in update mode: set to non-nil to enable ;;; auto-save in updates; set to a (positive) number to cause that many seconds ;;; delay before the auto-save and only auto-save (and -advance) on unambiguous ;;; items (i.e. where the recorded decisions completely disambiguate the new ;;; parses). ;;; (def-lkb-parameter *tree-automatic-update-p* nil) (def-lkb-parameter *tree-skeptical-update-p* nil) (def-lkb-parameter *tree-update-match-hook* nil) (def-lkb-parameter *tree-save-on-reject-p* t) (def-lkb-parameter *tree-display-semantics-p* t) (defparameter *tree-initialization-hook* nil) (defparameter *tree-completion-hook* nil) #+:debug (defvar %frame%) #+:debug (defvar %frame) ;; ;; _fix_me_ i am curious: why should the defstruct() be wrapped? ;; (eval-when (:load-toplevel :compile-toplevel :execute) (defstruct ctree edge id score flags symbol record ink)) (eval-when (:load-toplevel :compile-toplevel :execute) (clim:define-presentation-type ctree ())) (defun compare-parses (&optional (edges *parse-record*) &key input mode view) ;; JAC 6-Jan-2022 - removed now-obsolete code intended to fix up .from. ;; and .to. in each edge ;; (when edges (mp:run-function "Tree Comparison" #'(lambda () (let ((*tree-discriminants-mode* (or mode *tree-discriminants-mode*)) (*tree-display-view* (or view *tree-display-view*))) (compare edges :input input)))))) (defun compare (edges &key (runp t) input) (let* ((title (or input (format nil "Compare \"~a\"" (shortened-sentence-string (edge-leaves (first edges)) 128)))) (frame (apply #'clim:make-application-frame 'compare-frame :pretty-name title (unless runp (list :frame-manager nil))))) #+:debug (setf %frame% frame) (setf (compare-frame-chart frame) *chart-generation-counter*) (setf (compare-frame-runp frame) runp) (set-up-compare-frame frame edges :input input) (when runp (funcall #'clim:run-frame-top-level frame)) frame)) (defun run-compare-frame (frame) (clim:run-frame-top-level frame)) (defun set-up-compare-frame (frame edges &key (runp (compare-frame-runp frame)) input (display (let ((foo (getenv "DISPLAY"))) (and (stringp foo) (not (string= foo "")) foo)))) (setf (compare-frame-runp frame) runp) ;; ;; when called in error analysis mode, i.e. against the scoring results of ;; some stochastic parse selection model, throw out all edges that are not ;; part of the set of trees for closer inspection. ;; (when (compare-frame-inspect frame) (setf (compare-frame-display frame) :inspect) (loop with result = nil with inspect = (compare-frame-inspect frame) with all = (append (first inspect) (list (second inspect)) (third inspect)) for edge in edges for id = (edge-foo edge) for score = (find id all :key #'(lambda (foo) (rest (assoc :result-id foo)))) when score do (setf (edge-score edge) (rest (assoc :score score))) (push edge result) finally (setf edges (nreverse result)))) ;; ;; large sets of edges can take some time (and memory :-{) to display; query ;; for user confirmation before moving on. ;; (when (and runp display (integerp *tree-comparison-threshold*) (> (length edges) *tree-comparison-threshold*) (or *tree-automatic-update-p* ;; avoid implementation-dependent notify-user ... :style :question (null (lkb-y-or-n-p (format nil "Excessive Set of Trees (~a). Continue?" (length edges)))))) (frame-cursor frame :horizontal-scroll) (record-decision (make-decision :type :skip) frame) (return-from set-up-compare-frame :skip)) (when (and runp display) (frame-cursor frame :vertical-scroll)) ;; ;; _fix_me_ ;; probably, we should move this further down, until after extraction of ;; discriminants, so that start-up time is not reflected. ;; (6-jun-04; oe) ;; (setf (compare-frame-decisions frame) (list (make-decision :type :start))) (when (null (compare-frame-input frame)) (setf (compare-frame-input frame) (or input (format nil "~{~a~^ ~}" (edge-leaves (first edges)))))) ;; ;; wrap each edge into a `ctree' structure, so that we can record additional ;; information (associated parse tree symbol, CLIM output record, et al.). ;; (setf (compare-frame-trees frame) (loop with inspect = (compare-frame-inspect frame) with gold = (rest (assoc :result-id (second inspect))) for i from 0 for edge in edges for id = (if (numberp (edge-foo edge)) (edge-foo edge) i) for score = (edge-score edge) for symbol = (when (and *tree-use-node-labels-p* (eq (compare-frame-view frame) :classic)) (make-new-parse-tree edge)) for flags = (when (and gold (= id gold)) (list :gold)) for tree = (make-ctree :edge edge :id id :score score :flags flags :symbol symbol) collect tree when (and runp *tree-use-node-labels-p* (zerop (mod i 50))) do #+:allegro (format excl:*initial-terminal-io* "~&[~a] set-up-compare-frame(): expanding tree # ~a~%" (current-time :long :short) i) #-:allegro (identity nil) ; ccl complains if 'do' body is empty finally #+:allegro (when (and runp *tree-use-node-labels-p*) (format excl:*initial-terminal-io* "~&[~a] set-up-compare-frame(): rebuilt ~a tree~p.~%" (current-time :long :short) (length edges) (length edges))) #-:allegro (identity nil))) ;; ;; keep copy of original set of trees; needed for full resets ;; (setf (compare-frame-otrees frame) (copy-list (compare-frame-trees frame))) ;; ;; extract (minimal) set of elementary properties to discriminate analyses ;; (unless (compare-frame-exact frame) ;; ;; _fix_me_ ;; there are different usages of the 'exact' mode, including picking out ;; derivations among realization results that can be aligned (in various ;; interpretations of that term) with the 'gold' parse that provided the ;; input semantics for generation. i dimly recall that discriminants in ;; that setup ended up ill-defined (presumably because one and the same ;; edge can occur in different surface positions), hence we disabled the ;; extraction of discriminants below. in another 'exact' use case, viz. ;; finding matching lexical sub-trees in a lexical-only profile, it would ;; seem possible to extract discriminants, which would then have their ;; values determined by an update-discriminants() call below. however, we ;; would need another flag or something, to communicate whether or not the ;; compare frame would actually extract discriminants. so far, at least, ;; there is no practical benefit to having available discriminants for the ;; above use cases, however. (12-aug-11; oe) ;; (setf (compare-frame-discriminants frame) (find-discriminants edges :mode (compare-frame-mode frame) :tags (compare-frame-tags frame))) #+:allegro (when runp (format excl:*initial-terminal-io* "~&[~a] set-up-compare-frame(): found ~a discriminant~p.~%" (current-time :long :short) (length (compare-frame-discriminants frame)) (length (compare-frame-discriminants frame))))) ;; ;; preset discriminants from recorded decisions or gold decisions (during an ;; update); record `gold' discriminants that are no longer pertinent. ;; (unless (compare-frame-exact frame) (setf (compare-frame-lead frame) (preset-discriminants (compare-frame-discriminants frame) (compare-frame-preset frame) (compare-frame-gold frame) (compute-discriminant-skew edges)))) #+:allegro (when runp (loop initially (format excl:*initial-terminal-io* "~&~%[~@[~a~]] `~a'~%~%" (compare-frame-item frame) (compare-frame-input frame)) for foo in (compare-frame-lead frame) do (format excl:*initial-terminal-io* " [~2,'0d ~2,'0d] ~a ~a | ~a~@[ `~a'~]~%" (discriminant-start foo) (discriminant-end foo) (discriminant-state-as-string foo) (discriminant-toggle-as-string foo) (discriminant-key foo) (discriminant-value foo)) finally (when (compare-frame-lead frame) (format excl:*initial-terminal-io* "~%")))) (setf (compare-frame-edges frame) edges) (unless (compare-frame-exact frame) (recompute-in-and-out frame t)) ;; ;; when running in `exact match' update mode, adjust discriminants and most ;; everything else to zoom in on the matching derivation, if any ;; (when (compare-frame-exact frame) (setf (compare-frame-lead frame) nil) (when (compare-frame-discriminants frame) (update-discriminants (compare-frame-discriminants frame) (compare-frame-exact frame) t) #+:null (recompute-in-and-out frame)) (setf (compare-frame-in frame) nil) (setf (compare-frame-out frame) nil) (loop for edge in (compare-frame-edges frame) when (member edge (compare-frame-exact frame)) do (push edge (compare-frame-in frame)) else do (push edge (compare-frame-out frame)))) (when *tree-initialization-hook* (let* ((hook *tree-initialization-hook*) (extras (and (consp hook) (rest hook))) (hook (if (consp hook) (first hook) hook)) (hook (typecase hook (function hook) (symbol (and (fboundp hook) (symbol-function hook))) (string (ignore-errors (symbol-function (read-from-string hook))))))) (multiple-value-bind (result condition) (when (functionp hook) (ignore-errors (apply hook (cons frame extras)))) (cond ((= (length result) (length (compare-frame-discriminants frame))) (loop for discriminant in (compare-frame-discriminants frame) for state in result unless (eq state :unknown) do (setf (discriminant-toggle discriminant) state) (setf (discriminant-state discriminant) state) finally (recompute-in-and-out frame))) ((null result)) (t (format #+:allegro excl:*initial-terminal-io* #-:allegro *initial-terminal-io* "tree-initialization-hook(): ~ discriminant count mismatch (~a vs. ~a).~%" (length result) (length (compare-frame-discriminants frame))))) (when condition (clim:beep) (format #+:allegro excl:*initial-terminal-io* #-:allegro *initial-terminal-io* "tree-initialization-hook(): error `~a'.~%" (normalize-string (format nil "~a" condition))))))) ;; ;; extract some quantitative summary measures on update procedure; entirely ;; for record keeping purposes. ;; (when (and runp (compare-frame-update frame)) (push (cons :u-matches (loop for foo in (compare-frame-discriminants frame) count (discriminant-gold foo))) (compare-frame-update frame)) (push (cons :u-mismatches (length (compare-frame-lead frame))) (compare-frame-update frame)) (push (cons :u-pin (length (compare-frame-in frame))) (compare-frame-update frame)) (push (cons :u-pout (length (compare-frame-out frame))) (compare-frame-update frame))) ;; ;; in case the preferred tree was selected directly from the tree display, ;; we may not have recorded active decisions, i.e. the choice was reflected ;; in entailed discriminant states only. ;; (when (find :select (compare-frame-preset frame) :key #'discriminant-type) (loop for discriminant in (compare-frame-discriminants frame) for preset = (discriminant-preset discriminant) when preset do (setf (discriminant-state discriminant) (discriminant-state preset))) (recompute-in-and-out frame)) (when (find :reject (compare-frame-preset frame) :key #'discriminant-type) (setf (compare-frame-in frame) nil) (setf (compare-frame-out frame) edges)) (when (and runp *tree-skeptical-update-p*) (let ((gactive (compare-frame-gactive frame))) (when (and (numberp gactive) (zerop gactive)) (setf (compare-frame-in frame) nil) (setf (compare-frame-out frame) (compare-frame-edges frame))))) ;; ;; always update tree and discriminant state here: this will cause the frame ;; to redraw both lower panes. ;; (when (and runp display) #+:mcclim (when (clim:frame-panes frame) (clim:redisplay-frame-panes frame :force-p t)) #-:mcclim (clim:redisplay-frame-pane frame 'top :force-p t) #-:mcclim (clim:redisplay-frame-pane frame 'comment :force-p t) #-:mcclim (clim:redisplay-frame-pane frame 'status :force-p t)) (when display (update-trees frame)) ;; ;; _fix_me_ ;; need to disable input from frame for this to work reliably. ;; (14-oct-02 ; oe) (when (and runp *tree-automatic-update-p*) (when (numberp *tree-automatic-update-p*) (sleep *tree-automatic-update-p*)) (record-decision (make-decision :type (if (update-match-p frame) :save :flag)) frame) (return-from set-up-compare-frame :skip)) (setf (compare-frame-gactive frame) nil) (when (and runp display) (frame-cursor frame :default))) (defun reset-or-reconsider-compare-frame (frame &optional mode) #+:debug (setf %frame frame) (setf (compare-frame-trees frame) (compare-frame-otrees frame)) (setf (compare-frame-in frame) (compare-frame-edges frame)) (setf (compare-frame-out frame) nil) (loop for foo in (compare-frame-discriminants frame) do (setf (discriminant-time foo) (get-universal-time)) (setf (discriminant-gold foo) nil) (setf (discriminant-preset foo) nil) (setf (discriminant-state foo) :unknown) (setf (discriminant-toggle foo) :unknown)) ;; ;; preset discriminants from recorded decisions or gold decisions (during an ;; update); record `gold' discriminants that are no longer pertinent. ;; (unless (compare-frame-exact frame) (setf (compare-frame-lead frame) (preset-discriminants (compare-frame-discriminants frame) (compare-frame-preset frame) (compare-frame-gold frame) (compute-discriminant-skew (compare-frame-edges frame)) nil))) (unless (compare-frame-exact frame) (recompute-in-and-out frame t)) (unless (eq mode :reconsider) (when (find :reject (compare-frame-preset frame) :key #'discriminant-type) (setf (compare-frame-in frame) nil) (setf (compare-frame-out frame) (compare-frame-edges frame)))) ;; ;; always update tree and discriminant state here: this will cause the frame ;; to redraw both lower panes. ;; #+:mcclim (when (clim:frame-panes frame) (clim:redisplay-frame-panes frame :force-p t)) #-:mcclim (clim:redisplay-frame-pane frame 'top :force-p t) #-:mcclim (clim:redisplay-frame-pane frame 'comment :force-p t) #-:mcclim (clim:redisplay-frame-pane frame 'status :force-p t) (update-trees frame)) (defstruct decision type value (time (get-universal-time))) (defun record-decision (decision &optional frame) (if frame (let ((value (decision-value decision))) (when (discriminant-p value) (setf (discriminant-time value) (decision-time decision))) (push decision (compare-frame-decisions frame))) (clim:with-application-frame (frame) (record-decision decision frame)))) (defun comparison-top-font () (clim:make-text-style :sans-serif :roman 12)) (defun comparison-tree-font () (clim:make-text-style :sans-serif :roman (or *comparison-tree-font-size* 8))) (defun comparison-dependencies-font () (clim:make-text-style :sans-serif :roman (or *comparison-dependencies-font-size* 12))) (defun comparison-comment-font () (clim:make-text-style :sans-serif :roman (or *comparison-discriminant-font-size* 8))) (defun comparison-status-font () (clim:make-text-style :sans-serif :roman (or *comparison-discriminant-font-size* 8))) (defun comparison-discriminant-font () (clim:make-text-style :sans-serif :roman (or *comparison-discriminant-font-size* 8))) (declaim (notinline comparison-top-font comparison-tree-font comparison-dependencies-font comparison-comment-font comparison-status-font comparison-discriminant-font)) (clim:define-application-frame compare-frame () ((runp :initform 0 :accessor compare-frame-runp) (item :initform nil :accessor compare-frame-item) (input :initform nil :accessor compare-frame-input) (tags :initform nil :accessor compare-frame-tags) (start :initform nil :accessor compare-frame-start) (end :initform nil :accessor compare-frame-end) (edges :initform nil :accessor compare-frame-edges) (derivations :initform nil :accessor compare-frame-derivations) (trees :initform nil :accessor compare-frame-trees) (otrees :initform nil :accessor compare-frame-otrees) (preset :initform nil :accessor compare-frame-preset) (exact :initform nil :accessor compare-frame-exact) (gold :initform nil :accessor compare-frame-gold) (lead :initform nil :accessor compare-frame-lead) (mode :initform *tree-discriminants-mode* :accessor compare-frame-mode) (view :initform *tree-display-view* :accessor compare-frame-view) (show :initform *tree-results-show* :accessor compare-frame-show) (discriminants :initform nil :accessor compare-frame-discriminants) (decisions :initform nil :accessor compare-frame-decisions) (confidence :initform nil :accessor compare-frame-confidence) (in :initform nil :accessor compare-frame-in) (out :initform nil :accessor compare-frame-out) (display :initform :concise :accessor compare-frame-display) (threshold :initform *tree-display-threshold* :accessor compare-frame-threshold) (tstream :initform nil :accessor compare-frame-tstream) (chart :initform nil :accessor compare-frame-chart) (comment :initform " " :accessor compare-frame-comment) (version :initform nil :accessor compare-frame-version) (gversion :initform nil :accessor compare-frame-gversion) (gactive :initform nil :accessor compare-frame-gactive) (gderivation :initform nil :accessor compare-frame-gderivation) (inspect :initform nil :accessor compare-frame-inspect) (update :initform nil :accessor compare-frame-update) (ids :initform nil :accessor compare-frame-ids) (controller :initform nil :accessor compare-frame-controller)) (:panes (top (clim:outlining (:thickness 1) (clim:spacing (:thickness 2 :background clim:+white+) (clim:make-pane 'lkb-pane ; JAC 10-Dec-2018 - was clim:application-pane, and also below :display-function 'draw-top-window :text-cursor nil :text-style (comparison-top-font) :height '(#+:mcclim 1 #-:mcclim 1.1 :line) :min-height '(#+:mcclim 1 #-:mcclim 1.1 :line) :max-height '(#+:mcclim 1 #-:mcclim 1.1 :line) :end-of-line-action :allow :end-of-page-action :allow :display-time t :background clim:+white+ :foreground clim:+black+)))) (trees (clim:outlining (:thickness 1) (clim:scrolling (:scroll-bar :both :scroll-bars :both) ; CLIM spec ambiguous (clim:make-pane 'lkb-pane :display-function 'draw-trees-window :text-cursor nil :text-style (comparison-tree-font) :width *tree-display-trees-width* :height *tree-display-height* ;; no margins in Allegro CLIM; wrapping with spacing prevents scrolling #+:mcclim :text-margins #+:mcclim '(:left 3 :top 3 :bottom 3 :right 3) :end-of-line-action :allow :end-of-page-action :allow :display-time t :background clim:+white+ :foreground clim:+black+)))) (comment (clim:outlining (:thickness 1) (clim:spacing (:thickness 1 :background clim:+white+) (clim:make-pane 'lkb-pane :display-function 'draw-comment-window :text-cursor nil :text-style (comparison-comment-font) :height '(#+:mcclim 1 #-:mcclim 1.1 :line) :min-height '(#+:mcclim 1 #-:mcclim 1.1 :line) :max-height '(#+:mcclim 1 #-:mcclim 1.1 :line) :end-of-line-action :allow :end-of-page-action :allow :display-time t :background clim:+white+ :foreground clim:+black+)))) (status (clim:outlining (:thickness 1) (clim:spacing (:thickness 1 :background clim:+white+) (clim:make-pane 'lkb-pane :display-function 'draw-status-window :text-cursor nil :text-style (comparison-status-font) :height '(#+:mcclim 1 #-:mcclim 1.1 :line) :min-height '(#+:mcclim 1 #-:mcclim 1.1 :line) :max-height '(#+:mcclim 1 #-:mcclim 1.1 :line) :end-of-line-action :allow :end-of-page-action :allow :display-time t :background clim:+white+ :foreground clim:+black+)))) (discriminants (clim:outlining (:thickness 1) (clim:scrolling (:scroll-bar :both :scroll-bars :both) (clim:make-pane 'lkb-pane :display-function 'draw-discriminants-window :text-cursor nil :text-style (comparison-discriminant-font) :width *tree-display-discriminants-width* #+:mcclim :text-margins #+:mcclim '(:left 3 :top 3 :bottom 3 :right 3) :end-of-line-action :allow :end-of-page-action :allow :incremental-redisplay t :background clim:+white+ :foreground clim:+black+))))) (:layouts (:default (clim:vertically () top (clim:horizontally () trees (clim:vertically () comment status discriminants)))))) (defmethod initialize-instance :around ((frame compare-frame) &rest initargs) (if *manage-window-placement* (multiple-value-bind (left top width height) (compute-frame-position-and-size frame) (apply #'call-next-method frame :left left :top top :width width :height height initargs)) (call-next-method))) (define-compare-frame-command (com-exit-compare-frame :menu "Close") () (clim:with-application-frame (frame) (record-decision (make-decision :type :close) frame) (setf *tree-display-threshold* (compare-frame-threshold frame)) (if (compare-frame-controller frame) (mp:process-revoke-arrest-reason (compare-frame-controller frame) :wait) (clim:frame-exit frame)))) #+:null (define-compare-frame-command (com-first-compare-frame :menu "First") () (clim:with-application-frame (frame) (frame-cursor frame :horizontal-scroll) (record-decision (make-decision :type :first) frame) (when (compare-frame-controller frame) (mp:process-revoke-arrest-reason (compare-frame-controller frame) :wait)))) (define-compare-frame-command (com-previous-compare-frame :menu "Previous") () (clim:with-application-frame (frame) (frame-cursor frame :horizontal-scroll) (record-decision (make-decision :type :previous) frame) (when (compare-frame-controller frame) (mp:process-revoke-arrest-reason (compare-frame-controller frame) :wait)))) (define-compare-frame-command (com-next-compare-frame :menu "Next") () (clim:with-application-frame (frame) (frame-cursor frame :horizontal-scroll) (record-decision (make-decision :type :next) frame) (when (compare-frame-controller frame) (mp:process-revoke-arrest-reason (compare-frame-controller frame) :wait)))) #+:null (define-compare-frame-command (com-last-compare-frame :menu "Last") () (clim:with-application-frame (frame) (frame-cursor frame :horizontal-scroll) (record-decision (make-decision :type :last) frame) (when (compare-frame-controller frame) (mp:process-revoke-arrest-reason (compare-frame-controller frame) :wait)))) (define-compare-frame-command (com-reject-compare-frame :menu "Reject") () (clim:with-application-frame (frame) (record-decision (make-decision :type :reject) frame) (setf (compare-frame-in frame) nil) (setf (compare-frame-out frame) (compare-frame-edges frame)) (update-trees frame t :discriminant) (when *tree-save-on-reject-p* (record-decision (make-decision :type :save)) (when (compare-frame-controller frame) (mp:process-revoke-arrest-reason (compare-frame-controller frame) :wait))))) (define-compare-frame-command (com-clear-compare-frame :menu "Clear") () (clim:with-application-frame (frame) (record-decision (make-decision :type :clear) frame) (reset-discriminants frame))) (define-compare-frame-command (com-reset-compare-frame :menu "Reset") () (clim:with-application-frame (frame) (record-decision (make-decision :type :reset) frame) (reset-or-reconsider-compare-frame frame))) (define-compare-frame-command (com-reconsider-compare-frame :menu "Reconsider") () (clim:with-application-frame (frame) (record-decision (make-decision :type :reset) frame) (reset-or-reconsider-compare-frame frame :reconsider))) (define-compare-frame-command (com-ordered-compare-frame :menu "Ordered") () (clim:with-application-frame (frame) (setf (compare-frame-display frame) :ordered) (update-trees frame))) (define-compare-frame-command (com-concise-compare-frame :menu "Concise") () (clim:with-application-frame (frame) (setf (compare-frame-display frame) :concise) (update-trees frame))) (define-compare-frame-command (com-full-compare-frame :menu "Full") () (clim:with-application-frame (frame) (setf (compare-frame-display frame) nil) (update-trees frame))) (define-compare-frame-command (com-save-compare-frame :menu "Save") () (clim:with-application-frame (frame) (frame-cursor frame :horizontal-scroll) (record-decision (make-decision :type :save)) (when (compare-frame-controller frame) (mp:process-revoke-arrest-reason (compare-frame-controller frame) :wait)))) (define-compare-frame-command (com-confidence-compare-frame :menu "Confidence") () (clim:with-application-frame (frame) (pop-up-menu '(("High (3)" :value 3) ("Fair (2)" :value 2) ("Low (1)" :value 1) ("Zero (0)" :value 0)) #'(lambda (confidence) (setf (compare-frame-confidence frame) confidence))) (clim:redisplay-frame-pane frame 'top :force-p t))) (define-compare-frame-command (com-toggle-compare-frame :menu "Toggle") () (clim:with-application-frame (frame) (if (and (integerp *tree-display-threshold*) (= *tree-display-threshold* (compare-frame-threshold frame))) (setf *tree-display-threshold* nil) (setf *tree-display-threshold* (compare-frame-threshold frame))) (update-trees frame))) (defun draw-top-window (frame stream &rest rest) (declare (ignore rest)) ;; ;; first test whether we are displaying the window with an initialized frame ;; (if (compare-frame-edges frame) (clim:formatting-table (stream) (clim:formatting-row (stream) (let ((record (clim:formatting-cell (stream :align-x :center :min-width 950) (format stream "~:[~*~;(~a) ~][~a : ~a~@[ @ ~a~]] ~a" (compare-frame-item frame) (compare-frame-item frame) (length (compare-frame-in frame)) (length (compare-frame-out frame)) (let ((foo (compare-frame-confidence frame))) (when (and (integerp foo) (>= foo 0) (<= foo 3)) (aref #("zero" "low" "fair" "high") foo))) (compare-frame-input frame))))) (when (= (length (compare-frame-in frame)) 1) (recolor-record record clim:+blue+) (clim:replay record stream)) (when (update-match-p frame) (recolor-record record clim:+magenta+) (clim:replay record stream))))) (clim:formatting-table (stream) (clim:formatting-row (stream) (let ((record (clim:formatting-cell (stream :align-x :center :min-width 950) (format stream "- analyzing the parse forest; please wait -")))) (recolor-record record clim:+red+) (clim:replay record stream)))))) (defun draw-trees-window (frame stream &rest rest) (declare (ignore rest)) ;; ;; in case we were displaying the window with an uninitialized frame ;; (when (null (compare-frame-edges frame)) (return-from draw-trees-window)) (setf (compare-frame-tstream frame) stream) (when (and (compare-frame-trees frame) ; JAC - don't attempt to display an empty table (or (not (integerp *tree-display-threshold*)) (<= (length (compare-frame-trees frame)) *tree-display-threshold*))) (clim:formatting-table (stream :x-spacing "X") (loop for tree in (compare-frame-trees frame) do (setf (ctree-ink tree) clim:+foreground-ink+) (setf (ctree-record tree) (clim:with-new-output-record (stream) (clim:with-output-recording-options (stream :record t) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :center :align-y :top) (with-text-style-bold-face (stream (comparison-dependencies-font)) (format stream "~%[~a]" (ctree-id tree)))) (clim:formatting-cell (stream :align-x :left :align-y :center) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :left :align-y :top) (format stream "~@[(~a)~]~%" (ctree-score tree))) (clim:formatting-cell (stream :align-x :center :align-y :top) (clim:with-output-as-presentation (stream tree 'ctree :single-box t) (if (eq (compare-frame-view frame) :classic) (clim:format-graph-from-root (or (ctree-symbol tree) (setf (ctree-symbol tree) (make-new-parse-tree (ctree-edge tree)))) #'(lambda (node stream) (multiple-value-bind (s lex-p) (get-string-for-edge node) (if lex-p (with-text-style-bold-face (stream) (write-string s stream)) (write-string s stream)))) #'(lambda (node) (get node 'daughters)) :graph-type :parse-tree :stream stream :merge-duplicates nil :orientation :vertical :generation-separation 7 :move-cursor t :within-generation-separation 7 :center-nodes nil) (let* ((edge (ctree-edge tree)) (mrs (or (edge-mrs edge) (setf (edge-mrs edge) (ignore-errors (mrs::extract-mrs edge)))))) (when mrs (mrs:eds-output-psoa mrs :stream stream)))))))) ;; (terpri stream) ; JAC - not in conformance with the CLIM spec ))))) (when (and (compare-frame-trees frame) (null (rest (compare-frame-trees frame)))) (draw-trees-window-completion frame stream))) (update-tree-colours frame) #+:mcclim (clim:change-space-requirements stream))) ; update scroll bars (define-compare-frame-command (com-tree-popup) ((tree 'ctree :gesture (:select :menu nil))) (let ((mrsp *mrs-loaded*) (edge (ctree-edge tree))) (pop-up-menu `(("Yes" :value yes :active t) #+:null ("No" :value no :active t) ("Enlarged Tree" :value show) ("MRS" :value mrs :active ,mrsp) ("RMRS" :value rmrs :active ,mrsp) ("Indexed MRS" :value indexed :active ,mrsp) ("Scoped MRS" :value scoped :active ,mrsp) #+:logon ("UTool MRS" :value utool :active ,mrsp) ("Dependencies" :value dependencies :active ,mrsp) ("Rephrase" :value rephrase :active ,mrsp)) (yes (record-decision (make-decision :type :select :value edge)) (clim:with-application-frame (frame) (update-discriminants (compare-frame-discriminants frame) edge t) (recompute-in-and-out frame) (if (member (compare-frame-display frame) '(:concise :ordered :inspect)) (update-trees frame) (update-tree-colours frame)))) #+:null (no ;; ;; _fix_me_ ;; not sure what to do here: there may be no discriminant(s) to ;; exclusively rule out this single tree; we would presumably have ;; to create one and add it to the global list of discriminants; ;; not clear this is so desirable. (12-oct-02; oe) ;; (record-decision (make-decision :type :drop :value edge)) (clim:with-application-frame (frame) (update-discriminants (compare-frame-discriminants frame) edge nil) (if (member (compare-frame-display frame) '(:concise :ordered :inspect)) (update-trees frame) (update-tree-colours frame)))) (show (clim:with-application-frame (frame) (display-parse-tree nil nil :symbol (or (ctree-symbol tree) (setf (ctree-symbol tree) (make-new-parse-tree (ctree-edge tree)))) :title (format nil "Parse Tree #~a" (ctree-id tree)) :counter (compare-frame-chart frame)))) (mrs (when edge (ignore-errors (funcall 'show-mrs-window edge)))) (rmrs (when edge (ignore-errors (funcall 'show-mrs-rmrs-window edge)))) (indexed (when edge (ignore-errors (funcall 'show-mrs-indexed-window edge)))) (scoped (when edge (ignore-errors (funcall 'show-mrs-scoped-window edge)))) #+:logon (utool (when edge (ignore-errors (funcall 'show-mrs-utool-window edge)))) (dependencies (when edge (ignore-errors (funcall 'show-mrs-dependencies-window edge)))) (rephrase (let ((symbol (when (find-package :mt) (find-symbol "REPHRASE" :mt)))) (when (and symbol (fboundp symbol)) (funcall symbol edge))))))) (defun draw-trees-window-completion (frame stream) (let* ((hook *tree-completion-hook*) (hook (typecase hook (null nil) (function hook) (symbol (and (fboundp hook) (symbol-function hook))) (string (ignore-errors (symbol-function (read-from-string hook)))))) (tree (first (compare-frame-trees frame))) (edge (ctree-edge tree)) (mrs (or (edge-mrs edge) (ignore-errors (mrs::extract-mrs edge)))) (eds (when mrs (ignore-errors (mrs:eds-convert-psoa mrs))))) (multiple-value-bind (result condition) (when (functionp hook) (ignore-errors (funcall hook edge mrs))) (when condition (clim:beep) (format #+:allegro excl:*initial-terminal-io* #-:allegro *initial-terminal-io* "tree-completion-hook(): error `~a'.~%" (normalize-string (format nil "~a" condition)))) ;; if the hook result specifies a font/face/size then it must stay within the ;; CLIM 2.0 protocol, and not stray into the McCLIM font family protocol extension (let* ((comment (if (stringp result) result (rest (assoc :comment result)))) (result (unless (stringp result) result)) (font (rest (assoc :font result))) (face (rest (assoc :face result))) (size (rest (assoc :size result))) (style (when (or font face size) (clim:merge-text-styles (list font face size) (comparison-dependencies-font)))) (color (rest (assoc :color result))) (color (ignore-errors (apply #'clim:make-rgb-color color))) (bottomp (rest (assoc :bottom result))) (align (or (rest (assoc :align result)) :center))) (when (and comment (null bottomp)) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :center :align-y :top) (format stream " "))) (clim:with-drawing-options (stream :ink color) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :center :align-y :top) (format stream "")) ; JAC - removed superfluous (ctree-id tree) (clim:formatting-cell (stream :align-x align) (clim:with-text-style (stream style) (format stream "~%~a" comment)))))) (when (and eds (not (eq (compare-frame-view frame) :modern))) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :center :align-y :top) (format stream " "))) (let* ((status (mrs:eds-suspicious-p eds)) (orange (or #-:mcclim (clim:find-named-color "orange" (clim:frame-palette frame) :errorp nil) #+:mcclim clim:+orange+)) (color (cond ((member :cyclic status) clim:+red+) ((member :fragmented status) orange) (t (if (update-match-p frame) clim:+magenta+ clim:+blue+))))) (clim:with-drawing-options (stream :ink color) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :center :align-y :top) (with-text-style-bold-face (stream (comparison-dependencies-font)) (format stream "~%[~a]" (ctree-id tree)))) (clim:formatting-cell (stream :align-x :left) (clim:formatting-column (stream) (clim:formatting-cell (stream :align-x :left) (format stream "~@[(~a)~]~%" (ctree-score tree))) (clim:formatting-cell (stream :align-x :center) (clim:with-text-style (stream (comparison-dependencies-font)) (format stream "~a" eds))))))))) (when (and comment bottomp) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :center :align-y :top) (format stream " "))) (clim:with-drawing-options (stream :ink color) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :center :align-y :top) (format stream "")) ; JAC - removed superfluous (ctree-id tree) (clim:formatting-cell (stream :align-x align) (clim:with-text-style (stream style) (format stream "~%~a" comment)))))))))) (defun draw-comment-window (frame stream &rest rest) (declare (ignore rest)) (clim:formatting-table (stream) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :center :min-width 410) (let* ((comment (compare-frame-comment frame)) (comment (if (or (null comment) (equal comment "")) " " comment))) (format stream "~a" comment)))))) (defun draw-status-window (frame stream &rest rest) (declare (ignore rest)) (clim:formatting-table (stream) (clim:formatting-row (stream) (clim:formatting-cell (stream :align-x :center :min-width 410) (let ((version (compare-frame-version frame)) (gold (compare-frame-gversion frame))) (if (and version (not (equal version ""))) (format stream "~a~:[ ~;~]" version (or (null gold) (equal gold ""))) (format stream " ")) (when (and gold (not (equal gold ""))) (let ((record (clim:with-new-output-record (stream) (format stream "~a" gold)))) (recolor-record record (if (update-match-p frame) clim:+magenta+ clim:+blue+)) (clim:replay record stream)))))))) (eval-when (:load-toplevel :compile-toplevel :execute) (clim:define-presentation-type discriminant ())) (defun draw-discriminants-window (frame stream &rest rest) (declare (ignore rest)) ;; ;; in case we are displaying the window with an uninitialized frame ;; (when (or (null (compare-frame-edges frame)) (null (compare-frame-discriminants frame))) (return-from draw-discriminants-window)) (let ((discriminants (compare-frame-discriminants frame))) (clim:stream-set-cursor-position stream 0 0) (clim:formatting-table (stream :x-spacing "X") (loop for item in discriminants for record = (discriminant-record item) when record do (clim:clear-output-record record) unless (discriminant-hidep item) do (clim:formatting-row (stream) (setf (discriminant-record item) (clim:with-new-output-record (stream) (let ((ink (if (discriminant-gold item) (if (update-match-p frame) clim:+magenta+ clim:+blue+) clim:+foreground-ink+))) (clim:with-drawing-options (stream :ink ink) (clim:with-output-as-presentation (stream item 'discriminant) (clim:updating-output (stream :cache-value (discriminant-state item)) (clim:formatting-cell (stream :align-x :center :min-width "+") (write-string (discriminant-state-as-string item) stream))) (clim:updating-output (stream :cache-value (discriminant-toggle item)) (clim:formatting-cell (stream :align-x :center :min-width "+") (write-string (discriminant-toggle-as-string item) stream))) (clim:formatting-cell (stream :align-x :left) (format stream "~a" (discriminant-key item))) (clim:formatting-cell (stream :align-x :left) (format stream "~@[~a~]" (discriminant-value item))))))))))) #+:mcclim (clim:change-space-requirements stream))) (define-compare-frame-command (com-discriminant-popup) ((discriminant 'discriminant :gesture (:select :menu nil))) (pop-up-menu `(("Yes" :value yes) ("No" :value no) ("Unknown" :value unknown) (,(format nil "In Parses (~a)" (length (discriminant-in discriminant))) :value in) (,(format nil "Out Parses (~a)" (length (discriminant-out discriminant))) :value out)) (yes (record-decision (make-decision :type :yes :value discriminant)) (setf (discriminant-state discriminant) t) (setf (discriminant-toggle discriminant) t)) (no (record-decision (make-decision :type :no :value discriminant)) (setf (discriminant-state discriminant) nil) (setf (discriminant-toggle discriminant) nil)) (unknown (record-decision (make-decision :type :unknown :value discriminant)) (setf (discriminant-state discriminant) :unknown) (setf (discriminant-toggle discriminant) :unknown)) ;; ;; _fix_me_ ;; in concise mode, at least, make these only show trees that are ;; still available globally, i.e. ignore all trees that have become ;; out already. (20-jan-03; oe) ;; (in (show-parse-summary (discriminant-in discriminant))) (out (show-parse-summary (discriminant-out discriminant)))) (clim:with-application-frame (frame) (recompute-in-and-out frame) (update-trees frame t :discriminant))) (defun update-trees (frame &optional (redrawp t) (context nil) &key (runp (compare-frame-runp frame))) #+:mcclim (declare (ignore context)) (when runp (frame-cursor frame :vertical-scroll)) (if (null redrawp) (when runp (update-tree-colours frame)) (let ((in (compare-frame-in frame))) (when runp (loop for tree in (compare-frame-trees frame) when (ctree-record tree) do (clim:clear-output-record (ctree-record tree)) (setf (ctree-record tree) nil)) (loop for discriminant in (compare-frame-discriminants frame) for record = (discriminant-record discriminant) when record do (clim:clear-output-record record) (setf (discriminant-record discriminant) nil))) (case (compare-frame-display frame) (:ordered (setf (compare-frame-trees frame) (stable-sort (copy-list (compare-frame-otrees frame)) #'(lambda (foo bar) (let ((foop (member (ctree-edge foo) in :test #'eq)) (barp (member (ctree-edge bar) in :test #'eq))) (if (and foop (null barp)) t (let ((foo (ctree-id foo)) (bar (ctree-id bar))) (and (numberp foo) (numberp bar) (<= foo bar)))))))) (loop for discriminant in (compare-frame-discriminants frame) do (setf (discriminant-hidep discriminant) nil))) (:inspect (setf (compare-frame-trees frame) (stable-sort (copy-list (compare-frame-otrees frame)) #'(lambda (foo bar) (let ((flags (ctree-flags foo)) (foo (ctree-score foo)) (bar (ctree-score bar))) (when (and (numberp foo) (numberp bar)) (or (> foo bar) (and (= foo bar) (member :gold flags)))))))) (loop for discriminant in (compare-frame-discriminants frame) do (setf (discriminant-hidep discriminant) nil))) (:concise (setf (compare-frame-trees frame) (loop for tree in (compare-frame-otrees frame) when (member (ctree-edge tree) in :test #'eq) collect tree)) (loop with trees = (compare-frame-trees frame) with n = (length trees) for discriminant in (compare-frame-discriminants frame) for in = (discriminant-in discriminant) do (setf (discriminant-hidep discriminant) (or (not (eq (discriminant-state discriminant) :unknown)) (and (<= n (length in)) (not (loop for tree in trees for edge = (ctree-edge tree) for match = (find edge in :test #'eq) thereis (null match)))))))) (t (setf (compare-frame-trees frame) (copy-list (compare-frame-otrees frame))) (loop for discriminant in (compare-frame-discriminants frame) do (setf (discriminant-hidep discriminant) nil)))) #-:mcclim (when (and runp (not (eq context :tree))) (clim:redisplay-frame-pane frame 'trees :force-p t)) ;; ;; _fix_me_ ;; always force complete redraw: omitting this causes rather disturbing ;; glitches in the state and toggle displays in non-concise display mode ;; and the overlay of old ink with new ink in concise display; maybe our ;; drawing function needs improvement. (15-oct-02; oe) ;; (when runp #+:mcclim (when (clim:frame-panes frame) (clim:redisplay-frame-panes frame :force-p t)) #-:mcclim (clim::redisplay-frame-pane frame 'discriminants :force-p t) #-:mcclim (clim::redisplay-frame-pane frame 'top :force-p t)))) (when runp (frame-cursor frame :default))) (defun update-tree-colours (frame) (let ((stream (compare-frame-tstream frame))) (loop with in = (compare-frame-in frame) for tree in (compare-frame-trees frame) for ink = (cond ((not (member (ctree-edge tree) in :test #'eq)) clim:+red+) ((and (not (rest in)) (eq (ctree-edge tree) (first in))) (if (update-match-p frame) clim:+magenta+ clim:+blue+)) (t clim:+foreground-ink+)) for record = (ctree-record tree) unless (or (null record) (eq ink (ctree-ink tree))) do (setf (ctree-ink tree) ink) (recolor-record record ink) (clim:replay record stream)))) (defun recolor-record (record ink) (labels ((recolor-node (node) (when (clim:displayed-output-record-p node) ;; !!! the function (setf clim:displayed-output-record-ink) is not in any ;; CLIM specification (2.0, 2.2.2 or II), so this code is non-portable #-:mcclim (setf (clim:displayed-output-record-ink node) ink) #+:mcclim (ignore-errors (setf (slot-value node 'climi::ink) ink))) (clim:map-over-output-records #'recolor-node node))) (recolor-node record))) (defun frame-cursor (frame &optional (cursor :default)) (cond ((clim:application-frame-p frame) (let* ((sheet (clim:frame-top-level-sheet frame)) (port (clim:find-port)) (pointer (and port (clim:port-pointer port)))) #-:null (declare (ignore pointer)) (when (clim:sheetp sheet) (frame-cursor sheet cursor)) #+:null (when pointer (setf (clim:pointer-cursor pointer) cursor)))) ((clim:sheetp frame) (setf (clim:sheet-pointer-cursor frame) cursor) #+(and :allegro (not :mswindows)) (loop for child in (clim:sheet-children frame) ;; ;; _fix_me_ ;; although the CLIM 2.2 User Guide claims that all sheets (can) have ;; children, sheet-children() actually throws an exception on some of ;; the native Motif widgets; this calls for a bug report to Franz. ;; (16-oct-02; oe) unless (or (eq (class-of child) (find-class 'tk-silica::motif-menu-bar)) (eq (class-of child) (find-class 'tk-silica::motif-scroll-bar))) do (frame-cursor child cursor))))) (defun reset-discriminants (frame) (setf (compare-frame-trees frame) (compare-frame-otrees frame)) (setf (compare-frame-in frame) (compare-frame-edges frame)) (setf (compare-frame-out frame) nil) (loop for foo in (compare-frame-discriminants frame) do (setf (discriminant-time foo) (get-universal-time)) (setf (discriminant-state foo) :unknown) (setf (discriminant-toggle foo) :unknown) ;; ;; loose all memory of preset values at this point; no way back. ;; (setf (discriminant-preset foo) nil) (setf (discriminant-gold foo) nil)) (recompute-in-and-out frame t) (update-trees frame)) (defun recompute-in-and-out (frame &optional resetp) ;; ;; apply inference rules from [Carter, 1997] until a fixpoint is reached ;; _fix_me_ ;; now that some of the other parts are reasonably efficient, we can look at ;; sets of a thousand or more discriminants; propagation of discriminants ;; becomes noticeably sluggish with more than a few hundred. ;; (5-nov-02; oe) (let ((threshold *tree-display-threshold*) (initial (length (compare-frame-in frame))) (decision (first (compare-frame-decisions frame)))) (cond ((and (decision-p decision) (eq (decision-type decision) :reject)) (setf (compare-frame-in frame) nil) (setf (compare-frame-out frame) (compare-frame-edges frame)) ;; ;; always needs tree redraw, unless active set was empty before. ;; (not (zerop initial))) ((and (decision-p decision) (eq (decision-type decision) :select)) (let ((active (decision-value decision))) (setf (compare-frame-in frame) (list active)) (setf (compare-frame-out frame) (remove active (compare-frame-edges frame)))) t) (t (let ((donep nil)) (setf (compare-frame-in frame) (compare-frame-edges frame)) (setf (compare-frame-out frame) nil) (when resetp ;; ;; we risk loosing preset (gold) assignments here; maybe check for a ;; preset value and restore that here? (12-oct-02; oe) ;; ;; _fix_me_ ;; give more thought to propagation of decisions through updates: a ;; hard decision (i.e. toggle) may be lost during an upddate and only ;; survive as a soft decision (i.e. entailed state). over time, this ;; could lead to primarily soft annotations, and the distinction from ;; the original annotation cycle will be completely washed out. one ;; option could be to promote entailments from `gold' to hard when ;; performing the update, but that appears to blur the distinction ;; between actual decisions and entailment just as much. maybe have ;; additional values for toggle (and presumably state): inherited on ;; or off, or even hard inherited vs. soft inherited? ;; (14-oct-02; oe) ;; (loop for foo in (compare-frame-discriminants frame) for preset = (discriminant-preset foo) for gold = (discriminant-gold foo) do (setf (discriminant-state foo) (discriminant-toggle foo)) when gold do (setf (discriminant-state foo) (discriminant-state gold)) when preset do (setf (discriminant-state foo) (discriminant-state preset)))) (loop until donep do (setf donep t) (loop for foo in (compare-frame-discriminants frame) when (null (discriminant-state foo)) do (mark-out (discriminant-in foo) frame) when (eq (discriminant-state foo) t) do (mark-out (discriminant-out foo) frame)) (setf (compare-frame-in frame) (set-difference (compare-frame-edges frame) (compare-frame-out frame) :test #'eq)) (loop for foo in (compare-frame-discriminants frame) when (null (intersection (discriminant-in foo) (compare-frame-in frame) :test #'eq)) do (when (discriminant-state foo) (setf (discriminant-state foo) nil) (setf donep nil)) else when (subsetp (compare-frame-in frame) (discriminant-in foo) :test #'eq) do (when (not (discriminant-state foo)) (setf (discriminant-state foo) t) (setf donep nil))))) (and (integerp threshold) (or (and (> initial threshold) (<= (length (compare-frame-in frame)) threshold)) (and (<= initial threshold) (> (length (compare-frame-in frame)) threshold)))))))) (defun mark-out (edges frame) (loop for edge in edges do (pushnew edge (compare-frame-out frame) :test #'eq) (setf (compare-frame-in frame) (remove edge (compare-frame-in frame))))) (defun update-match-p (frame) (when (and *tree-automatic-update-p* *tree-update-match-hook*) (let ((hook (typecase *tree-update-match-hook* (null nil) (function *tree-update-match-hook*) (symbol (and (fboundp *tree-update-match-hook*) (symbol-function *tree-update-match-hook*))) (string (ignore-errors (symbol-function (read-from-string *tree-update-match-hook*))))))) (when hook (ignore-errors (funcall hook frame)))))) ;;; ;;; from here on, HTML output routines; this should probably be reorganized, so ;;; that the comparison class is generic, and only the CLIM-specific parts are ;;; in the segregated directory. (6-aug-03; oe) ;;; (defun html-compare (frame &key (stream t) (indentation 0)) #+:debug (setf %frame% frame) (let ((treep (or (not (integerp *tree-display-threshold*)) (<= (length (compare-frame-trees frame)) *tree-display-threshold*)))) (format stream "~v,0t~%~ ~v,0t ~%~v,0t ~%~ ~v,0t ~%" indentation indentation indentation indentation (compare-frame-item frame) (compare-frame-item frame) (compare-frame-input frame) (length (compare-frame-in frame)) (length (compare-frame-out frame)) (let ((foo (compare-frame-confidence frame))) (when (and (integerp foo) (>= foo 0) (<= foo 3)) (aref #("zero" "low" "fair" "high") foo))) indentation) (when treep (format stream "~v,0t ~%" indentation)) (let ((mrsp (when (and *tree-display-semantics-p* (compare-frame-trees frame) (null (rest (compare-frame-trees frame)))) (let ((edge (ctree-edge (first (compare-frame-trees frame))))) (or (edge-mrs edge) (when (edge-dag edge) (mrs::extract-mrs edge))))))) (format stream "~v,0t ~%~v,0t ~%~v,0t
~%~ ~v,0t ~:[~*~;(~a) ~]~a [~a : ~a~@[ @ ~a~]]
~%" indentation) (html-trees frame :stream stream :indentation (+ indentation 6)) (format stream "~%~v,0t ~%" indentation mrsp) (if (not mrsp) (html-discriminants frame :stream stream :onlyp (not treep) :indentation (+ indentation 6)) #+:mrs (mrs::output-mrs1 mrsp 'mrs::html stream)))) (format stream "~v,0t
" indentation indentation indentation)) (defun html-trees (frame &key (stream t) (indentation 0)) (unless (and (integerp *tree-display-threshold*) (> (length (compare-frame-trees frame)) *tree-display-threshold*)) (loop initially (format stream "~v,0t~%" indentation) finally (format stream "~v,0t
" indentation) with in = (compare-frame-in frame) for tree in (compare-frame-trees frame) for color = (unless (member (ctree-edge tree) in :test #'eq) "red") do (format stream "~v,0t ~%~v,0t ~ ~%~v,0t ~ ~%~v,0t ~ ~%~v,0t ~ ~ ~%~v,0t
[~a]
~:[~* ~;~a~]
~%~v,0t ~ ~%" indentation indentation indentation indentation (ctree-id tree) indentation (ctree-score tree) (ctree-score tree) indentation indentation) (html-tree (ctree-edge tree) :tree (ctree-symbol tree) :indentation (+ indentation 6) :color color :stream stream) (format stream "~%~v,0t ~%" indentation)))) (defun html-discriminants (frame &key (stream t) onlyp (indentation 0)) (let ((discriminants (compare-frame-discriminants frame))) (format stream "~v,0t~%" indentation onlyp) (loop for i from 0 for item in discriminants for state = (discriminant-state-as-string item) for toggle = (discriminant-toggle item) unless (discriminant-hidep item) do (format stream "~v,0t ~%~v,0t ~ ~:[~%~v,0t ~;~2*~]~ ~%~v,0t ~ ~%~v,0t ~ ~@[~]~%" indentation indentation (eq (compare-frame-display frame) :concise) state indentation indentation i indentation indentation (eq toggle :unknown) indentation (eq toggle t) indentation (null toggle) indentation indentation (discriminant-key item) indentation (discriminant-value item))) ; JAC: removed superfluous arg (format stream "~v,0t
~a~%~v,0t ~ ~a~a
" indentation))) (defun ptb-compare-hook (frame &key size) (let* ((input (compare-frame-input frame)) (input (if (stringp input) (let ((symbol (find-symbol "READ-PTB-FROM-STRING" :tsdb))) (when symbol (funcall (symbol-function symbol) input)) input))) (comment (compare-frame-comment frame))) (when (and (consp input) (stringp comment)) (setf (compare-frame-input frame) comment) (lui-display-tree input comment :size size)) nil)) #+:null (setf lkb::*tree-initialization-hook* '("lkb::ptb-compare-hook" :size 8))