;;; Gash --- Guile As SHell ;;; Copyright © 2018 Jan (janneke) Nieuwenhuizen ;;; ;;; This file is part of Gash. ;;; ;;; Gash is free software; you can redistribute it and/or modify it ;;; under the terms of the GNU General Public License as published by ;;; the Free Software Foundation; either version 3 of the License, or (at ;;; your option) any later version. ;;; ;;; Gash is distributed in the hope that it will be useful, but WITHOUT ANY ;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ;;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ;;; details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with Gash. If not, see . (define-module (gash geesh) #:use-module (srfi srfi-1) #:use-module (ice-9 match) #:use-module (ice-9 pretty-print) #:use-module (gash builtins) #:use-module (gash gash) #:use-module (gash io) #:export ( parse parse-string )) (catch #t (lambda _ (use-modules (gash parser))) (lambda (key . args) #t)) (define (parse port) (let ((parse-tree (read-sh-all port))) (when (> %debug-level 1) (format (current-error-port) "parse-tree:\n") (pretty-print parse-tree (current-error-port))) (let ((ast (parse-tree->script parse-tree))) (when (> %debug-level 1) (format (current-error-port) "transformed:\n") (pretty-print ast (current-error-port))) (let* ((script (match ast (((or 'command 'pipeline) _ ...) `(script ,ast)) ((_ ...) `(script ,@ast)) (_ `(script ,ast)))) (tracing-script (annotate-tracing script))) (when (> %debug-level 0) (format (current-error-port) "script:\n") (pretty-print tracing-script (current-error-port))) tracing-script)))) (define (parse-string string) (call-with-input-string string parse)) (define (parse-tree->script tree) (define (transform o) (when (> %debug-level 2) (format (current-error-port) "transform:\n") (pretty-print o (current-error-port))) (match o ((' body ...) `(begin ,@(map transform body))) ((' ((' (left ...))) right) `(pipeline ,@(map transform left) ,(transform right))) ((' (' (left ...) right)) `(pipeline ,@(map transform left) ,(transform right))) ((' (left right)) `(pipeline ,(transform left) ,(transform right))) ((' command) `(command ,(transform command))) ((' command ...) `(command ,@(map transform command))) (((and ref (' _)) words ...) `(word ,(transform ref) ,@(map transform words))) ((' var) `(variable ,var)) ((' (var (and value ((? symbol?) _ ...)))) `(assignment ,(transform var) ,(transform value))) ((' (var (value ...))) `(assignment ,(transform var) (word ,@(map transform value)))) ((' (var value)) `(assignment ,(transform var) ,(transform value))) (((and kwote (' _)) word) `(word ,(transform kwote) ,(transform word))) ((') `(doublequotes "")) ((' words ...) `(doublequotes (word ,@(map transform words)))) (((and quote (' _)) tail ...) `(word ,(transform quote) ,@(map transform tail))) ((' cmd) `(substitution ,(transform cmd))) ((' (expression then)) `(if-clause ,(transform expression) ,(transform then))) ((' (('<< 0 string)) pipeline) (let ((pipeline (transform pipeline))) `(pipeline (display ,(transform string)) ,@(match pipeline (('command command ...) `(,pipeline)) (('pipeline commands ...) commands))))) ((' (name (sequence)) body) `(for ,(transform name) (lambda _ (split ,(transform sequence))) (lambda _ ,(transform body)))) ((' (name sequence) body) `(for ,(transform name) (lambda _ (split ,(transform sequence))) (lambda _ ,(transform body)))) ((? string?) o) (((? string?) _ ...) `(word ,@(map re-word o))) ((_ ...) (map transform o)) (_ o))) (transform tree)) (define (re-word word) (match word ((? string?) word) (((and h (? string?)) t ...) `(word ,h ,@(map (compose re-word parse-tree->script) t))) (_ (parse-tree->script word)))) (define (annotate-tracing script) (match script (('pipeline command) `(pipeline ,(trace (list command)) ,command)) (('pipeline commands ...) `(pipeline ,(trace commands) ,@commands)) (('command command ...) `(pipeline ,(trace (list script)) ,script)) ((_ ...) (map annotate-tracing script)) (_ script)))