-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparser.lisp
57 lines (49 loc) · 1.68 KB
/
parser.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
(defpackage :elis/parser
(:use :cl)
(:export :parse))
(in-package :elis/parser)
(defvar *eof-value* '#:eof)
(defvar *elis-readtable*
(let ((readtable (copy-readtable)))
(setf (readtable-case readtable) :preserve)
(set-macro-character #\. 'dot-reader nil readtable)
(set-macro-character #\| 'char-reader nil readtable)
readtable))
(defun char-reader (stream char)
(declare (ignore stream))
(case char
(#\| :pipe)
(otherwise (string char))))
(defun dot-reader (stream char)
(declare (ignore char))
(cond ((eql #\. (peek-char nil stream nil))
(read-char stream)
:parent-directory)
(t
:current-directory)))
(defun read-ahead (stream &optional eof-error-p eof-value)
(let ((*read-eval* nil)
(*readtable* *elis-readtable*))
(handler-case (read stream eof-error-p eof-value)
(end-of-file (e)
(error 'elis/conditions:parse-input-error
:message (princ-to-string e))))))
(defun tokenize (string)
(with-input-from-string (stream string)
(loop :for eof-error-p := t :then nil
:for arg := (read-ahead stream eof-error-p *eof-value*)
:until (eq arg *eof-value*)
:collect (typecase arg
(keyword arg)
(symbol (string arg))
(otherwise arg)))))
(defun construct-execute (command)
(cons :execute command))
(defun parse (string)
(let* ((tokens (tokenize string))
(commands (split-sequence:split-sequence :pipe tokens)))
(if (alexandria:length= commands 1)
(construct-execute (first commands))
(cons :pipe
(mapcar #'construct-execute
commands)))))