Basic support for special reading behaviour on a property-basis. Added property functions and some basic default cases.

This commit is contained in:
Shinmera 2014-10-29 11:05:08 +01:00
parent 0a26d30452
commit d6908c8732
5 changed files with 149 additions and 24 deletions

View File

@ -23,12 +23,13 @@ See the definition of the LET block.")
(:documentation "Resolves THING to a value that makes sense for LASS.
By default the following types are handled:
NULL: NIL
STRING: the THING itself
ARRAY: the variable stored in *VARS* under THING
KEYWORD: Colon-prefixed, downcased symbol-name of THING
SYMBOL: Downcased symbol-name of THING
T: PRINC-TO-STRING of THING")
NULL: NIL
STRING: the THING itself
ARRAY: the variable stored in *VARS* under THING
KEYWORD: Colon-prefixed, downcased symbol-name of THING
SYMBOL: Downcased symbol-name of THING
PATHNAME: If designating an image, base64 encoded inline image data.
T: PRINC-TO-STRING of THING")
(:method ((thing null))
NIL)
(:method ((thing string))
@ -164,6 +165,27 @@ Returns a list with the RESOLVEd SELECTOR.")
(:method ((selector T))
(list (resolve selector))))
(defgeneric consume-item (item readable-list)
(:method (thing readable-list)
(error "Don't know what to do with ~s (not part of a property)." thing))
(:method ((subblock list) readable-list)
(values
NIL
subblock))
(:method ((property symbol) readable-list)
(if (keywordp property)
(values
(let ((propvals ()))
(loop for (next fullp) = (multiple-value-list (peek readable-list))
while fullp
do (etypecase next
(keyword (return))
(list (return))
(T (push (consume readable-list) propvals))))
(cons property (nreverse propvals)))
NIL)
(call-next-method))))
(defgeneric compile-block (header fields)
(:documentation "Compiles the block with given HEADER and FIELDS list.
By default, the following case is handled:
@ -186,28 +208,25 @@ Special handling of blocks may occur.
See DEFINE-SPECIAL-BLOCK.")
(:method (selector fields)
(let ((selector (compile-selector selector))
(readable (make-readable-list fields))
(props ())
(subblocks ()))
;; compute props and subblocks
(blocks ()))
;; compute props and blocks
(flet ((add-prop (prop)
(when prop
(let ((prop (nreverse prop)))
(dolist (prop (compile-property (car prop) (cdr prop)))
(push prop props))))))
(loop with prop = ()
for field in fields
do (etypecase field
(keyword
(add-prop prop)
(setf prop (list field)))
(list
(dolist (subblock (compile-block (list selector (car field)) (cdr field)))
(push subblock subblocks)))
(T (push field prop)))
finally (add-prop prop)))
(dolist (prop (compile-property (car prop) (cdr prop)))
(push prop props))))
(add-block (block)
(when block
(dolist (block (compile-block (list selector (car block)) (cdr block)))
(push block blocks)))))
(loop until (empty-p readable)
for (prop block) = (multiple-value-list (consume-item (consume readable) readable))
do (add-prop prop)
(add-block block)))
;; Returns list of blocks with ours consed to front
(cons (make-block selector (nreverse props))
(nreverse subblocks)))))
(nreverse blocks)))))
(defun compile-sheet (&rest blocks)
"Compiles a LASS sheet composed of BLOCKS.

View File

@ -10,7 +10,7 @@
(defsystem lass
:name "LASS"
:version "0.2.0"
:version "0.3.0"
:license "Artistic"
:author "Nicolas Hafner <shinmera@tymoon.eu>"
:maintainer "Nicolas Hafner <shinmera@tymoon.eu>"
@ -18,7 +18,9 @@
:homepage "https://github.com/Shinmera/LASS"
:serial T
:components ((:file "package")
(:file "readable-list")
(:file "compiler")
(:file "property-funcs")
(:file "writer")
(:file "lass")
(:file "special"))

54
property-funcs.lisp Normal file
View File

@ -0,0 +1,54 @@
#|
This file is a part of LASS
(c) 2014 Shirakumo http://tymoon.eu (shinmera@tymoon.eu)
Author: Nicolas Hafner <shinmera@tymoon.eu>
|#
(in-package #:org.tymoonnext.lass)
(defvar *property-functions* (make-hash-table :test 'equalp))
(defun property-function (name)
(gethash (string name) *property-functions*))
(defun (setf property-function) (function name)
(setf (gethash (string name) *property-functions*)
function))
(defmacro define-property-function (name args &body body)
`(setf (property-function ,(string name))
#'(lambda ,args ,@body)))
(defmacro define-simple-property-function (name args)
`(define-property-function ,name ,args
(format NIL ,(format NIL "~(~a~)(~{~*~~a~^,~})" name args)
,@(loop for arg in args collect `(resolve ,arg)))))
(defun resolve-function (function &rest args)
(let ((resolver (property-function function)))
(if resolver
(apply resolver args)
(format NIL "~(~a~)(~{~a~^,~})" function args))))
(defmethod resolve ((thing list))
(apply #'resolve-function (car thing) (cdr thing)))
;; We redefine the method here in order to delegate to property functions
;; if they do actually exist.
(defmethod consume-item ((property symbol) readable-list)
(if (keywordp property)
(values
(let ((propvals ()))
(loop for (next fullp) = (multiple-value-list (peek readable-list))
while fullp
do (etypecase next
(keyword (return))
(list
(let ((resolver (property-function (car next))))
(if resolver
(push (consume readable-list) propvals)
(return))))
(T (push (consume readable-list) propvals))))
(cons property (nreverse propvals)))
NIL)
(call-next-method)))

37
readable-list.lisp Normal file
View File

@ -0,0 +1,37 @@
#|
This file is a part of LASS
(c) 2014 Shirakumo http://tymoon.eu (shinmera@tymoon.eu)
Author: Nicolas Hafner <shinmera@tymoon.eu>
|#
(in-package #:org.tymoonnext.lass)
(defclass readable-list ()
((inner :initarg :list :initform () :accessor inner)))
(defun make-readable-list (&optional list)
(make-instance 'readable-list :list list))
(defmacro with-empty-check ((lis) &body body)
`(if (null (inner ,lis))
(values NIL NIL)
(values (progn ,@body) T)))
(defun empty-p (readable-list)
(null (inner readable-list)))
(defun consume (readable-list)
(with-empty-check (readable-list)
(pop (inner readable-list))))
(defun peek (readable-list)
(with-empty-check (readable-list)
(first (inner readable-list))))
(defun advance (readable-list)
(with-empty-check (readable-list)
(setf (inner readable-list)
(cdr (inner readable-list)))))
(defun pushback (item readable-list)
(push item (inner readable-list)))

View File

@ -6,6 +6,19 @@
(in-package #:org.tymoonnext.lass)
;;; FUNCS
(macrolet ((define-properties (&rest rest)
`(progn
,@(loop for (name args) on rest by #'cddr
collect `(define-simple-property-function ,name ,args)))))
(define-properties
url (url)
rgb (red green blue)
rgba (red green blue alpha)
hsv (hue saturation value)
hsva (hue saturation value alpha)))
(define-property-function hex (hex) (format NIL "#~a" hex))
;;; BLOCKS
(define-special-block charset (charset)