[Phemlock-cvs] CVS update: phemlock/src/clim/exp-syntax.lisp phemlock/src/clim/foo.lisp
Gilbert Baumann
gbaumann at common-lisp.net
Fri Jul 9 15:16:14 UTC 2004
Update of /project/phemlock/cvsroot/phemlock/src/clim
In directory common-lisp.net:/tmp/cvs-serv24576/src/clim
Modified Files:
foo.lisp
Added Files:
exp-syntax.lisp
Log Message:
moved syntax highlighting out to another file.
Date: Fri Jul 9 08:16:14 2004
Author: gbaumann
Index: phemlock/src/clim/foo.lisp
diff -u phemlock/src/clim/foo.lisp:1.1.1.1 phemlock/src/clim/foo.lisp:1.2
--- phemlock/src/clim/foo.lisp:1.1.1.1 Fri Jul 9 06:38:09 2004
+++ phemlock/src/clim/foo.lisp Fri Jul 9 08:16:14 2004
@@ -422,9 +422,11 @@
(first (cons dummy-line the-sentinel)) )
(setf (slot-value hunk 'ts) (clim:make-text-style :fixed :roman :normal))
- '(setf (slot-value hunk 'ts) (clim:make-device-font-text-style
+ #+NIL
+ (setf (slot-value hunk 'ts) (clim:make-device-font-text-style
(clim:port stream)
"-*-lucidatypewriter-medium-r-*-*-*-120-*-*-*-*-iso8859-1"))
+ (setf (slot-value hunk 'ts) (clim:make-text-style :sans-serif :roman :normal))
(setf (slot-value hunk 'cw) (clim:text-style-width (slot-value hunk 'ts)
(clim-hunk-stream hunk)))
(setf (slot-value hunk 'ch) (+ 2 (clim:text-style-height (slot-value hunk 'ts)
@@ -632,463 +634,6 @@
(sleep .1)))
(device-note-read-wait device nil)))
-(defun line-syntax-info (line)
- (getf (line-plist line) 'syntax-info-4))
-
-(defun (setf line-syntax-info) (value line)
- (setf (getf (line-plist line) 'syntax-info-4) value))
-
-(defun hi::ensure-syntax-marks (line)
- (let ((si (line-syntax-info line)))
- (cond ((null si)
- (setf si
- (setf (line-syntax-info line)
- (cons :frob nil)))))
- (setf (line-syntax-info line)
- (ensure-syntax-marks-2 line si))))
-
-(defun ensure-syntax-marks-2 (line si)
- (destructuring-bind (signature . font-marks) si
- (cond ((eq signature (line-signature line))
- si)
- (t
- ;; work to do
- ;; 1. remove font marks
- (dolist (fm font-marks)
- (hi::delete-font-mark fm))
- (setf font-marks nil)
- (let ((in-string-p nil)
- (in-comment-p nil))
- (loop for p from 0 below (line-length line) do
- (cond ((char= (line-character line p) #\")
- (unless in-comment-p
- (if in-string-p
- (push (hi::font-mark line p 0) font-marks)
- (push (hi::font-mark line (1+ p) 2) font-marks))
- (setf in-string-p (not in-string-p))))
- ((char= (line-character line p) #\;)
- (unless (or in-string-p in-comment-p)
- (setf in-comment-p t)
- (push (hi::font-mark line p 1) font-marks))))))
- (cons (line-signature line) font-marks)
- ))))
-
-;; second approach:
-;; syntax-info: (signature start-state end-state font-marks)
-;;
-
-(defun empty-syntax-info ()
- (list :frob nil nil nil))
-
-(defun hi::ensure-syntax-marks (line)
- (let ((si (line-syntax-info line)))
- (cond ((null si)
- (setf si
- (setf (line-syntax-info line) (empty-syntax-info)))))
- (setf (line-syntax-info line)
- (ensure-syntax-marks-2 line si))))
-
-(defun line-syntax-info* (line)
- (cond ((null line)
- (list :frob nil (list nil) nil))
- (t
- (hi::ensure-syntax-marks line))))
-
-(defun ensure-syntax-marks-2 (line si)
- (destructuring-bind (signature start end font-marks) si
- (let ((prev-end (third (line-syntax-info* (line-previous line)))))
- (cond ((and (eq signature (line-signature line))
- (equal start prev-end))
- ;; no work
- si)
- (t
- ;; work to do, but first remove old font marks
- (dolist (fm font-marks)
- (hi::delete-font-mark fm))
- (setf font-marks nil)
- ;; now do the highlighting
- (let ((in-string-p (first prev-end))
- (in-comment-p nil))
- (when in-string-p
- (push (hi::font-mark line 0 2) font-marks))
- (loop for p from 0 below (line-length line) do
- (unless (and (> p 0)
- (char= (line-character line (1- p)) #\\))
- (cond ((char= (line-character line p) #\")
- (unless in-comment-p
- (if in-string-p
- (push (hi::font-mark line p 0) font-marks)
- (push (hi::font-mark line (1+ p) 2) font-marks))
- (setf in-string-p (not in-string-p))))
- ((char= (line-character line p) #\;)
- (unless (or in-string-p in-comment-p)
- (setf in-comment-p t)
- (push (hi::font-mark line p 1) font-marks))))))
- (print (list :ending :with (list in-string-p)) *trace-output*)
- ;; return new info
- (list (line-signature line)
- prev-end
- (list in-string-p)
- font-marks) ))))))
-
-
-;;;; ------------------------------------------------------------------------------------------
-;;;; Syntax Highlighting
-;;;;
-
-;; This still is only proof of concept.
-
-;; We define highlighting by parsing the buffer content with a simple
-;; recursive descend parser. The font attributes for each character are
-;; then derived from the parser state. Each line remembers the start and
-;; end parser state for caching. If the start parser state is the same as
-;; the end parser state of the previous line no reparsing needs to be done.
-;; Lines can change and if a line changes its end parser state is
-;; considered to be unknown. So if you change a line syntax highlighting of
-;; all following lines is potentially invalid. We avoid reparsing all of
-;; the rest of the buffer by three means: First we access syntax markup in
-;; a lazy fashion; if a line isn't displayed we don't need its syntax
-;; markup. Second when while doing reparsing the newly computed end state
-;; is the same as the old end state reparsing stops, because this end state
-;; then matches the start state of the next line. Third when seeing an open
-;; paren in the very first column, we assume that a new top-level
-;; expression starts.
-
-;; These recursive descend parsers are written in a mini language which
-;; subsequently is compiled to some "byte" code and interpreted by a
-;; virtual machine. For now we don't allow for parameters or return values
-;; of procedures and so a state boils down to the current procedure, the
-;; instruction pointer and the stack of saved activations.
-
-;; This mini language allows to define procedures. Within a body of a
-;; procedure the following syntax applies:
-
-;; stmt -> (IF <cond> <tag>) If <cond> evaluates to true, goto <tag>.
-;; <cond> can be any lisp expression and has
-;; the current look-ahead character available
-;; in the variable 'ch'.
-;; <tag> A symbol serving as the target for GOs.
-;; (GO <tag>) Continue execution at the indicated label.
-;; (CONSUME) Consume the current lookahead character and
-;; read the next one putting it into 'ch'.
-;; (CALL <proc>) Call another procedure
-;; (RETURN) Return from the current procedure
-
-;; What the user sees is a little different. The function ME expands its
-;; input to the above language. Added features are:
-
-;; (IF <cond> <cons> [<alt>]) IF is modified to take statements instead
-;; of branch targets
-;; (PROGN {<stmt>}*) Mainly because of IF, PROGN is introduced.
-;; Note that the body can defined new branch
-;; targets, which also are available from outside
-;; of it.
-;; (WHILE <cond> {<stmt>}*)
-;; (COND {(<cond> {<stmt>}*)}*)
-
-;; This mini-language for now is enough to write interesting recursive
-;; descend parsers.
-
-(eval-when (compile eval load)
- (defun me (form)
- (cond ((atom form)
- (list form))
- (t
- (ecase (car form)
- ((IF)
- (destructuring-bind (cond cons &optional alt) (cdr form)
- (let ((L1 (gensym "L."))
- (L2 (gensym "L.")))
- (append (list `(IF (not ,cond) ,L1))
- (me cons)
- (list `(GO ,L2))
- (list L1)
- (and alt (me alt))
- (list L2)))))
- ((WHILE)
- (destructuring-bind (cond &rest body) (cdr form)
- (let ((exit (gensym "EXIT."))
- (loop (gensym "LOOP.")))
- (append (list loop)
- (list `(if (not ,cond) ,exit))
- (me `(progn , at body))
- (list `(go ,loop))
- (list exit)))))
- ((COND)
- (cond ((null (cdr form)) nil)
- (t
- (me
- `(if ,(caadr form) (progn ,@(cdadr form))
- (cond ,@(cddr form)))))))
- ((CONSUME RETURN) (list form))
- ((PROGN) (mapcan #'me (cdr form)))
- ((GO) (list form))
- ((CALL) (list form))))))
-
- (defun ass (stmts)
- (let ((ip 0)
- (labels nil)
- (fixups nil)
- (code (make-array 0 :fill-pointer 0 :adjustable t)))
- (loop for stmt in stmts
- do
- (cond ((atom stmt)
- (push (cons stmt ip) labels))
- ((eq (car stmt) 'go)
- (vector-push-extend :go code) (incf ip)
- (push ip fixups)
- (vector-push-extend (cadr stmt) code) (incf ip))
- ((eq (car stmt) 'if)
- (vector-push-extend :if code) (incf ip)
- (vector-push-extend `(lambda (ch) (declare (ignorable ch)) ,(cadr stmt))
- code)
- (incf ip)
- (push ip fixups)
- (vector-push-extend (caddr stmt) code) (incf ip))
- ((eq (car stmt) 'call)
- (vector-push-extend :call code) (incf ip)
- (vector-push-extend `',(cadr stmt) code) (incf ip))
- ((eq (car stmt) 'consume)
- (vector-push-extend :consume code) (incf ip))
- ((eq (car stmt) 'return)
- (vector-push-extend :return code) (incf ip))
- (t
- (incf ip)
- (vector-push-extend stmt code))))
- (loop for fixup in fixups do
- (let ((q (cdr (assoc (aref code fixup) labels))))
- (unless q
- (error "Undefined label ~S." (aref code fixup)))
- (setf (aref code fixup) q)))
- code)))
-
-(defmacro defstate (name stuff &rest body)
- stuff
- `(setf (gethash ',name *parsers*)
- (vector ,@(coerce (ass (append (me `(progn , at body))
- (list '(return))))
- 'list))))
-
-(defvar *parsers* (make-hash-table))
-
-(defstate initial ()
- (while t
- (call sexp)))
-
-(defstate comment ()
- loop
- (cond ((char= ch #\newline)
- (consume)
- (return))
- (t
- (consume)
- (go loop))))
-
-(defstate bq ()
- (consume) ;consume `
- (call sexp))
-
-(defstate uq ()
- (consume) ;consume `
- (call sexp))
-
-(defstate sexp ()
- loop
- (call skip-white*) ;skip possible white space and comments
- (cond ((char= ch #\() (call list))
- ((char= ch #\`) (call bq))
- ((char= ch #\') (call bq))
- ((char= ch #\,) (call uq))
- ((char= ch #\;) (call comment))
- ((char= ch #\") (call string))
- ((char= ch #\#) (call hash))
- ((or (alphanumericp ch) (find ch "-+*/"))
- (call atom))
- (t
- ;; hmm
- (consume)
- (go loop))))
-
-(defstate hash ()
- (consume)
- (cond ((char= ch #\\) (call char-const))
- ((char= ch #\+) (call hash-plus))
- ((char= ch #\')
- (consume)
- (call sexp))
- (t
- (call sexp))))
-
-(defstate char-const ()
- (consume) ;\\
- (cond ((or (alphanumericp ch) (find ch "-+*/"))
- (call atom))
- (t
- (consume))))
-
-(defstate string ()
- (consume)
- (while t
- (cond ((char= ch #\\)
- (consume)
- (consume))
- ((char= ch #\")
- (consume)
- (return))
- (t
- (consume)))))
-
-(defstate atom ()
- (while (or (alphanumericp ch) (find ch "-+*/"))
- (consume)))
-
-(defstate list ()
- (consume) ;consume open-paren
- (while t
- (call skip-white*) ;skip possible white space
- (cond ((char= ch #\))
- (consume)
- (return))
- (t
- (call sexp)))))
-
-(defstate skip-white* ()
- loop
- (while (member ch '(#\space #\tab #\newline #\return #\page))
- (consume))
- (cond ((char= ch #\;)
- (call comment)
- (go loop))
- (t
- (return))))
-
-(defstate hash-plus ()
- (consume) ;#\+
- (call sexp) ;cond
- (call sexp) ;form
- )
-
-;; --------------------
-
-(defun step** (state char)
- (let* (fun ip code)
- (labels ((fetch ()
- (prog1 (aref code ip) (incf ip)))
- (sync (fun* ip*)
- (setf fun fun*
- ip ip*
- code (or (gethash fun *parsers*)
- (error "No such fun: ~S." fun))))
- (exit ()
- (sync (pop state) (pop state)))
- (save ()
- (push ip state)
- (push fun state)))
- (exit)
- (loop
- (ecase (fetch)
- (:IF
- (let ((cond (fetch))
- (target (fetch)))
- (when (funcall cond char)
- (setf ip target))))
- (:CONSUME
- (save)
- (return-from step** state))
- (:RETURN
- '(print (list :return state) *trace-output*)
- (exit)
- ;;(print (list :dada state))
- )
- (:CALL
- (let ((new-fun (fetch)))
- '(print (list :call new-fun) *trace-output*)
- (save)
- (sync new-fun 0)))
- (:GO
- (setf ip (fetch))))))))
-
-(defun dodo (string)
- (let ((state (list 'initial 0)))
- (loop for c across string do
- (setf state (step** state c))
- (let ((q (member-if (lambda (x) (member x '(string bq uq comment))) state)))
- (case (car q)
- (comment (format t "/~A" c))
- (bq (princ (char-upcase c)))
- (uq (princ c))
- ((nil) (princ c)))))
- state))
-
-;;;;;;;;;;;;;
-
-(defun empty-syntax-info ()
- (list :frob nil (list 'initial 0) nil))
-
-(defun hi::ensure-syntax-marks (line)
- (let ((si (line-syntax-info line)))
- (cond ((null si)
- (setf si
- (setf (line-syntax-info line) (empty-syntax-info)))))
- (setf (line-syntax-info line)
- (ensure-syntax-marks-2 line si))))
-
-(defun line-syntax-info* (line)
- (cond ((null line)
- (empty-syntax-info))
- (t
- (hi::ensure-syntax-marks line))))
-
-(defun ensure-syntax-marks-2 (line si)
- (destructuring-bind (signature start end font-marks) si
- (let ((prev-end (third (line-syntax-info* (line-previous line)))))
- (cond ((and (eq signature (line-signature line))
- (equal start prev-end))
- ;; no work
- si)
- (t
- ;; work to do, but first remove old font marks
- (dolist (fm font-marks)
- (hi::delete-font-mark fm))
- (setf font-marks nil)
- ;; now do the highlighting
- (let ((state prev-end)
- (last-font 0))
- ;;(print `(:begin ,state) *trace-output*)
- (loop for p from 0 below (line-length line) do
- (let ((ch (line-character line p)))
- (setf state (step** state ch))
- (let ((font (state-font state)))
- (unless (eq font last-font)
- (push (hi::font-mark line p font) font-marks)
- (setf last-font font)))))
- (setf state (step** state #\newline))
- ;; hack
- (let ((s (line-string line)) p1 p2)
- (when (and (eql 0 (search "(def" s))
- (setf p1 (position #\space s))
- (setf p2 (position #\space s :start (1+ p1))))
- (push (hi::font-mark line (1+ p1) 5) font-marks)
- (push (hi::font-mark line p2 0) font-marks)))
- ;;(print (list prev-end state) *trace-output*)
- ;; return new info
- (list (line-signature line)
- prev-end
- state
- font-marks) ))))))
-
-(defun state-font (state)
- (cond ((member 'hash-plus state)
- 6)
- (t
- (let ((q (member-if (lambda (x) (member x '(string bq uq comment hash-plus))) state)))
- (case (car q)
- (comment 1)
- (bq 2)
- (uq 3)
- (string 4)
- (hash-plus 6)
- ((nil) 0))))))
;;;
More information about the Phemlock-cvs
mailing list