(in-package #:monparser) (defmacro literal (word) (when (not (stringp word)) (error "Literal only accepts strings as input.")) (let ((binding-list '()) (name-list '())) (loop :for c :across word :do (when c (let ((name (gensym))) (push name name-list) (push `(,name (unit ,c)) binding-list)))) `(comp ,(reverse binding-list) (coerce ,(cons 'list (reverse name-list)) 'string)))) (defparameter nothing (new nil)) (defun optional (p) (one-of p nothing)) (defun many (p) (comp ((x p) (xs (if x (optional (many p)) (fail "Parsing result is empty.")))) (cons x xs))) (defun repeat (p min &optional (max 0)) (if (> min 0) (comp ((x p) (xs (repeat p (1- min) (1- max)))) (cons x xs)) (if (> max 0) (comp ((x (optional p)) (xs (repeat p 0 (if x (1- max) 0)))) (if x (cons x xs) x)) nothing))) (defun whitespace? (x) (some (lambda (y) (char= x y)) '(#\Space #\Newline #\Return #\Tab))) (defparameter whitespace (optional (many (unit whitespace?)))) (defun separated-list (p separator) (comp ((v p) (sep (optional separator)) (vn (if sep (separated-list p separator) nothing))) (cons v vn))) (defun surround (p left &optional right) (comp ((_ left) (body p) (_ (or right left))) body))