| 1 | #| |
|---|
| 2 | Copyright (C) 2007 David Owen <dsowen@fugue88.ws> |
|---|
| 3 | |
|---|
| 4 | This library is free software; you can redistribute it and/or |
|---|
| 5 | modify it under the terms of the GNU Lesser General Public |
|---|
| 6 | License as published by the Free Software Foundation; either |
|---|
| 7 | version 2.1 of the License, or (at your option) any later version. |
|---|
| 8 | |
|---|
| 9 | This library is distributed in the hope that it will be useful, |
|---|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 12 | Lesser General Public License for more details. |
|---|
| 13 | |
|---|
| 14 | You should have received a copy of the GNU Lesser General Public |
|---|
| 15 | License along with this library; if not, write to the Free Software |
|---|
| 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|---|
| 17 | |# |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | (defpackage #:dso-lex |
|---|
| 22 | (:documentation "Allows the definition of lexers. See DEFLEXER.") |
|---|
| 23 | (:use #:cl #:cl-ppcre) |
|---|
| 24 | (:export #:deflexer)) |
|---|
| 25 | |
|---|
| 26 | (in-package #:dso-lex) |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | |
|---|
| 30 | (defun combine (regex-list) |
|---|
| 31 | (let ((mapped (mapcar |
|---|
| 32 | (lambda (regex) `(:register (:regex ,regex))) |
|---|
| 33 | regex-list))) |
|---|
| 34 | (when (rest mapped) (setq mapped `((:alternation ,@mapped)))) |
|---|
| 35 | `(:sequence (:flags :single-line-mode-p) :start-anchor ,@mapped))) |
|---|
| 36 | |
|---|
| 37 | (defmacro deflexer (name &body body) |
|---|
| 38 | "Defines lexers, called as a function of the given NAME. The body |
|---|
| 39 | consists of token-class definitions, each being a list of a regular |
|---|
| 40 | expression, the name of the class, and an optional filter. |
|---|
| 41 | |
|---|
| 42 | Currently, matching is done using *only* priority (first match wins), |
|---|
| 43 | and does not look for the longest match." |
|---|
| 44 | (let ((regex (combine (mapcar #'first body))) |
|---|
| 45 | (classes (map 'vector #'second body)) |
|---|
| 46 | (filters (map 'vector #'third body))) |
|---|
| 47 | `(defun ,name (input &optional (start 0)) |
|---|
| 48 | (let ((parts (nth-value 3 (scan (quote ,regex) input :start start)))) |
|---|
| 49 | (let ((idx (position-if #'identity parts))) |
|---|
| 50 | (when idx |
|---|
| 51 | (let ((end (aref parts idx))) |
|---|
| 52 | (let ((image (make-array (- end start) |
|---|
| 53 | :element-type 'character |
|---|
| 54 | :displaced-to input |
|---|
| 55 | :displaced-index-offset start)) |
|---|
| 56 | (filter (aref ,filters idx))) |
|---|
| 57 | (values (aref ,classes idx) |
|---|
| 58 | (if filter (funcall filter image) image) |
|---|
| 59 | end))))))))) |
|---|