;;; Alef Lazily Evaluates Functions ;;; (C) 2008-2009 Dr. Gergo ERDI (in-package :alef) (defclass csharp-writer () ((out-stream :accessor out-stream :initarg :out-stream) (line-start-p :accessor line-start-p :initform t) (block-depth :accessor block-depth :initform 0) (class-path :accessor class-path :initform (list)))) (defconstant +indent-size+ 4) (defconstant +chars/escape+ "(),.-+*/{}^=<>_?!@:") (defun write-newline (csharp-writer) (write-char #\Newline (out-stream csharp-writer)) (setf (line-start-p csharp-writer) t)) (defun ensure-newline (csharp-writer) (when (not (line-start-p csharp-writer)) (write-newline csharp-writer))) (defun start-line (csharp-writer) (when (line-start-p csharp-writer) (loop repeat (* (block-depth csharp-writer) +indent-size+) do (write-char #\Space (out-stream csharp-writer)))) (setf (line-start-p csharp-writer) nil)) (defun escape-string (string) (labels ((escape-p (char) (find char +chars/escape+)) (escape-char (char) (format nil "_u~D_" (char-code char)))) (with-output-to-string (s) (loop for start = 0 then (1+ pos) for pos = (position-if #'escape-p string :start start) do (write-sequence string s :start start :end pos) when pos do (write-sequence (escape-char (char string pos)) s) while pos)))) (defun unescape-string (string) (with-output-to-string (s) (loop for start = 0 then (1+ pos) for pos = (position #\_ string :test #'char= :start start) do (write-sequence string s :start start :end pos) when pos do (let* ((pos* (position #\_ string :test #'char= :start (incf pos 2))) (code (parse-integer (with-output-to-string (s) (write-sequence string s :start pos :end pos*))))) (write-char (code-char code) s) (setf pos pos*)) while pos))) (defun write-code (csharp-writer string &key (escape nil) newline) (loop for start = 0 then (1+ pos) for pos = (position #\Newline string :start start) do (progn (start-line csharp-writer) (write-sequence (if escape (escape-string string) string) (out-stream csharp-writer) :start start :end pos)) when (or newline pos) do (write-newline csharp-writer) while pos)) (defun write-code/escape (csharp-writer string &key newline) (write-code csharp-writer string :escape t :newline newline)) (defun start-block (csharp-writer) (ensure-newline csharp-writer) (write-code csharp-writer "{" :newline t) (incf (block-depth csharp-writer))) (defun finish-block (csharp-writer) (decf (block-depth csharp-writer)) (ensure-newline csharp-writer) (write-code csharp-writer "}" :newline t)) (defmacro write-block (csharp-writer &body body) `(progn (start-block ,csharp-writer) ,@body (finish-block ,csharp-writer)))