(import srfi-1) (define (combinator? c) (combinator-ref c)) (define (listify-selector-suffix selector) (cond ((symbol? selector) (listify-selector-suffix (symbol->string selector))) ((string? selector) (let loop ((types +selector-types+)) (if (pair? types) (if (eq? (cdar types) (string-ref selector 0)) (list '= (caar types) (substring selector 1)) (loop (cdr types))) (error "Invalid SCSS selector" selector)))) (else selector))) (define (merge-selectors parent-selector child-selector) (match parent-selector (#f child-selector) ((or (? symbol?) ((or (? combinator?) '=) _ ...)) (match child-selector (((? combinator? combinator) selector ...) (cons* combinator parent-selector selector)) (('& selector-suffix) (let recur ((parent-selector parent-selector)) (match parent-selector (((? combinator? combinator) selectors ... last-selector) `(,combinator ,@selectors ,(recur last-selector))) (else (match (listify-selector-suffix selector-suffix) (('= selector-type arg) (list '= selector-type parent-selector arg)) (else (error "Invalid nested SCSS+ selector suffix" selector-suffix))))))) ((and ((cominator selector ...) ...) selectors) (map (lambda (s) (merge-selectors parent-selector s)) selectors)) (else (error "Invalid nested SCSS+ selector" child-selector)))) ((selectors ...) (map (lambda (s) (merge-selectors s child-selector)) selectors)) (else (error "Invalid nested SCSS+ parent selector" parent-selector)))) (define (expand-ruleset ruleset #!optional parent-selector) (match ruleset ((selector declarations ...) (let ((selector (merge-selectors parent-selector selector))) (let loop ((declarations declarations) (result '(()))) (match declarations (() (match result ((() tail ...) tail) ((head tail ...) (cons (cons selector (reverse! head)) tail)))) (((and ((nested-selector ...) nested-declarations ...) nested-ruleset) more-declarations ...) (loop more-declarations (append result (expand-ruleset nested-ruleset selector)))) (((and (property value ...) declaration) more-declarations ...) (loop more-declarations (cons (cons declaration (car result)) (cdr result)))))))) (else (error "Invalid SCSS+ ruleset" ruleset)))) (define (scss-plus->scss rulesets) (append-map expand-ruleset rulesets))