(define-module (language python spec) #:use-module (language python guilemod) #:use-module ((parser stis-parser lang python3-parser) #:prefix python-parser:) #:use-module ((language python module python) #:select ()) #:use-module (language python compile) #:use-module (language python completer) #:use-module (rnrs io ports) #:use-module (ice-9 pretty-print) #:use-module (ice-9 readline) #:use-module (system base compile) #:use-module (system base language) #:use-module (language scheme compile-tree-il) #:use-module (language scheme decompile-tree-il) #:use-module (ice-9 rdelim) #:export (python *python-debug*)) ;;; ;;; Language definition ;;; (define *python-debug* #f) (define (trace . x) (when *python-debug* (let () (define port (open-file "python-log.txt" "a")) (with-output-to-port port (lambda () (pretty-print x) (car (reverse x)))) (close port))) (car (reverse x))) (define (logging-compile int? exp) "Compile the Python expression EXP while optionally logging intermediate values." (trace (comp int? (trace (python-parser:p (trace exp)))))) (define (read-or-compile int? port exp) "Compile the Python expression EXP or read a new one from PORT." (if (string-null? exp) (read port) (logging-compile int? exp))) (define (python-eval exp) "Evaluate the Python expression EXP." (eval (logging-compile #t exp) (current-module))) (define (ignore-errors proc) "Run PROC and ignore all errors." (catch #t (lambda () (proc)) (const #f))) (define (int) (ignore-errors (lambda () (not (fluid-ref (@@ (system base compile) %in-compile)))))) (define (in) (ignore-errors (lambda () (fluid-set! (@@ (system base compile) %in-compile) #t)))) (define mapper (make-weak-key-hash-table)) (define python-reader-wrap (lambda (port env) (if (int) (read-or-compile #t port (read-line port)) (let lp ((port2 (hash-ref mapper port))) (if port2 (read port2) (let ((port2 (open-input-string (read-or-compile #f port (read-string port))))) (use-modules (language python guilemod)) (in) (hash-set! mapper port port2) (lp port2))))))) (ignore-errors (lambda () (set! (@@ (ice-9 readline) *readline-completion-function*) (complete-python python-eval)))) (define-language python #:title "python" #:reader python-reader-wrap #:compilers `((tree-il . ,compile-tree-il)) #:decompilers `((tree-il . ,decompile-tree-il)) #:evaluator (lambda (x module) (primitive-eval x)) #:printer write #:make-default-environment (lambda () ;; Ideally we'd duplicate the whole module hierarchy so that `set!', ;; `fluid-set!', etc. don't have any effect in the current environment. (let ((m (make-fresh-user-module))) ;; Provide a separate `current-reader' fluid so that ;; compile-time changes to `current-reader' are ;; limited to the current compilation unit. (module-define! m 'current-reader (make-fluid)) ;; Default to `simple-format', as is the case until ;; (ice-9 format) is loaded. This allows ;; compile-time warnings to be emitted when using ;; unsupported options. (module-set! m 'format simple-format) m)))