git.fiddlerwoaroof.com
Raw Blame History
;;;; 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))))))