git.fiddlerwoaroof.com
php_pre.lisp
85d5b584
 ;;;; php_pre.lisp
 
 (in-package #:php_pre)
 
 (defclass statement ()
   ((statement-keyword :initarg :keyword :accessor statement-keyword)
    (param :initarg :param :accessor param)
    (body :initarg :body :accessor body)))
 
 (defmethod print-object ((object statement) s)
   (print-unreadable-object (object s :type t :identity t)
     (format s "~a (~d expressions)"
 	    (statement-keyword object)
 	    (length (body object)))))
 
 (defun make-statement (type param body)
   (make-instance 'statement :keyword type :param param :body body))
 
 (defun .constituent ()
   (.is #'alpha-char-p))
 
 (defun .keyword ()
   (.first
    (.map 'string (.constituent))))
 
 (defun .whitespace-char ()
   (.or (.char= #\space)
        (.is-not #'graphic-char-p)))
 
 (defun .comment ()
   (.or (.first
 	(.prog2 (.string= "//")
 		(.word-list)
 		(.char= #\newline)
 		(.optional (.whitespace))))
        (.first
 	(.prog2 (.string= "/*")
 		(.map 'string (.and (.not (.string= "*/"))
 				    (.item)))
 		(.string= "*/")
 		(.optional (.whitespace))))))
 
 (defun .whitespace ()
   (.first (.map 'string (.whitespace-char))))
 
 (defun .word-terminator ()
   (.or (.whitespace-char)
        (.is (lambda (x)
 	      (or (char= x #\{)
 		  (char= x #\})
 		  (char= x #\})
 		  (char= x #\;))))))
 
 (defun .array-el ()
   (.let* ((first (.first (.map 'string
 			       (.prog2 (.optional (.whitespace))
 				       (.is-not (lambda (it)
 						  (member it '(#\= #\,))))
 				       (.optional (.whitespace))))))
 	  (second (.optional (.progn (.string= "=>")
 				     (.optional (.whitespace))
 				     (.first
 				      (.map 'string
 					    (.is-not #'char= #\,))))))
 	  (divider (.optional (.char= #\,))))
     divider
     (.identity (cons first second))))
 
 (defun .php-array ()
   (.let* ((begin (.char= #\[))
 	  (els (.map 'list (.array-el) :at-least 0))
 	  (end (.char= #\])))
     (.identity (list :array begin els end))))
 
 (defun .word ()
   (.or (.first (.concatenate 'string
 			     (.string= "'")
 			     (.map 'string (.is-not #'char= #\'))
 			     (.string= "'")))
        (.first (.concatenate 'string
 			     (.string= "\"")
 			     (.map 'string (.is-not #'char= #\"))
 			     (.string= "\"")))
        (.first (.map 'string (.and (.not (.word-terminator))
 				   (.item))))))
 
 (defun .word-list (&optional (word-parser '.word))
   (.map 'list
 	(.progn (.optional (.whitespace))
 		(.first (funcall word-parser)))))
 
 (defun .line (&optional (word-parser '.word))
   (.prog1 (.word-list)
 	  (.progn (.optional (.whitespace))
 		  (.char= #\;))))
 
 (defun .paren-word ()
   (.map 'string (.and (.not (.or (.word-terminator)
 				 (.char= #\( )
 				 (.char= #\) )))
 		      (.item))))
 
 (defun .statement-list ()
   (.map 'list (.or (.prog1 (.first (.word-list))
 			   (.optional (.whitespace))
 			   (.char= #\;))
 		   (.progn (.optional (.whitespace))
 			   (.first (.statement))))
 	:at-least 0))
 
 (defun .statement-start ()
   (.let* ((type (.progn (.optional (.whitespace))
 			(.first (.keyword))))
 	  (param (.optional (.or (.prog2 (.progn (.optional (.whitespace))
 						 (.char= #\( ))
 					 (.word-list)
 					 (.progn (.optional (.whitespace))
 						 (.char= #\) )))
 				 (.word-list))))
 	  (_ (.progn (.whitespace)
 		     (.char= #\{))))
     (.identity (cons type param))))
 
 (defun .statement ()
   (.let* ((start (.progn (.prog1 (.map 'list
 				       (.progn (.optional (.whitespace))
 					       (.comment))
 				       :at-least 0)
 				 (.optional (.whitespace)))
 			 (.statement-start)))
 	  (statements (.progn (.whitespace)
 			      (.statement-list)))
 	  (_ (.progn (.optional (.whitespace))
 		     (.char= #\}))))
     (destructuring-bind (type . param) start
       (.identity (make-statement type param statements)))))
 
 (defun slurp (fn)
   (with-open-file (s fn)
     (let ((result (make-string (file-length s))))
       (read-sequence result s)
       result)))
 
 (defun .main-parser ()
   (.map 'list (.or (.prog1 (.word-list) (.char= #\;))
 		   (.first
 		    (.progn (.optional (.whitespace))
 			    (.statement))))))