Skip to content

Instantly share code, notes, and snippets.

@mbakhterev
Created January 13, 2017 08:44
Show Gist options
  • Save mbakhterev/8cb09f4d427c9ead7f5e279626ebebc3 to your computer and use it in GitHub Desktop.
Save mbakhterev/8cb09f4d427c9ead7f5e279626ebebc3 to your computer and use it in GitHub Desktop.
(define (bash-command-line cl)
; Будем всё обрабатывать циклом конечного автомата. В Scheme написано, что
; в простых случаях конструирования подстрок (функция substring) всё сводится
; к вычислению указателя на начало и длины в буфере исходной строки. Поэтому
; активно используем строковые операции, и остаток неразобранной строки
; вычисляем через substring.
;
; Для уменьшения громоздкости кода разумно иметь вспомогательные функции. А он
; действительно получается громоздким
(define (select-state str n)
; Определяем состояние, в которой должна перейти обработка, начиная с
; символа n. Это может быть и конец строки.
(if (>= n (string-length str))
#:end-of-string
(let ((ch (string-ref str n)))
(cond
((char-set-contains? char-set:whitespace ch) 'skip-mode)
((eq? #\' ch) #:quote-mode)
(else #:plain-mode)))))
(define (skip state str)
; На основании состояния пропускаем символы в строке. В состоянии plain надо
; быть готовыми встретить escape-последовательность. Кажется удобным, чтобы
; строка была откорректирована всегда так, чтобы ценное содержимое
; начиналось с 0 символа. То есть, если надо разобрать 'a', то где-то во вне
; первая кавычка будет откушена.
(case state
; Пропуск всего до кавычки или \-escape
((#:quote-mode) (string-index str (char-set-adjoin char-set:empty #\' #\\)))
; Пропуск всего до кавычки или пробела
((#:plain-mode) (string-index str (char-set-adjoin char-set:whitespace #\')))
; Пропуск пробелов
((#:skip-mode) (string-skip str char-set:whitespace))))
(define (select-rest state str n)
; На основании состояния вычисляем остаток строки для обработки. Сдвиги на
; один символ вперёд для пропуска пробелов и для разбора строк в кавычках.
(case state
((#:end-of-string) #f)
((#:quote-mode #:skip-mode) (substring str (+ 1 n)))
((#:plain-mode) (substring str n))))
(let loop ((state (select-state cl 0))
(current "")
(rest (select-rest (select-state cl 0) cl 0))
(result (list)))
(let ((n (skip state rest)))
(case state
((#:end-of-string) (reverse result))
))))
@kovisoft
Copy link

Thank you for the bug report. It seems that the problem is caused by the #\\) series of characters in line 32. Normally paredit ignores parens that are escaped by a backslash, but this time there is a double-backslash before the opening parenthesis, so it is actually not escaped.

Until the fix is ready, a quick workaround is to put a space after the double backshash, like this: #\\ ).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment