(define-module (language python compile) #:use-module (ice-9 match) #:use-module (ice-9 control) #:use-module (oop pf-objects) #:use-module (oop goops) #:use-module (language python dict) #:use-module (language python exceptions) #:use-module (language python yield) #:use-module (language python for) #:use-module (language python try) #:use-module (language python list) #:use-module (language python string) #:use-module (language python number) #:use-module (language python def) #:use-module (ice-9 pretty-print) #:export (comp)) (define-syntax-rule (aif it p x y) (let ((it p)) (if it x y))) (define-inlinable (C x) `(@@ (language python compile) ,x)) (define-inlinable (N x) `(@@ (language python number) ,x)) (define-inlinable (Y x) `(@@ (language python yield) ,x)) (define-inlinable (T x) `(@@ (language python try) ,x)) (define-inlinable (F x) `(@@ (language python for) ,x)) (define-inlinable (E x) `(@@ (language python exceptions) ,x)) (define-inlinable (L x) `(@@ (language python list) ,x)) (define-inlinable (A x) `(@@ (language python array) ,x)) (define-inlinable (S x) `(@@ (language python string) ,x)) (define-inlinable (Se x) `(@@ (language python set) ,x)) (define-inlinable (D x) `(@@ (language python def) ,x)) (define-inlinable (Di x) `(@@ (language python dict) ,x)) (define-inlinable (O x) `(@@ (oop pf-objects) ,x)) (define-inlinable (G x) `(@ (guile) ,x)) (define-inlinable (H x) `(@ (language python hash) ,x)) (define s/d 'set!) (define-syntax clear-warning-data (lambda (x) (set! (@@ (system base message) %dont-warn-list) '()) #f)) (define (dont-warn v) (set! (@@ (system base message) %dont-warn-list) (cons v (@@ (system base message) %dont-warn-list)))) (define *prefixes* (make-fluid '())) (define (add-prefix id) (if (fluid-ref (@@ (system base compile) %in-compile)) (fluid-set! *prefixes* (cons id (fluid-ref *prefixes*))) (begin (when (not (module-defined? (current-module) '__prefixes__)) (module-define! (current-module) '__prefixes__ (make-fluid '()))) (let ((p (module-ref (current-module) '__prefixes__))) (fluid-set! p (cons id (fluid-ref p))))))) (define (is-prefix? id) (if (fluid-ref (@@ (system base compile) %in-compile)) (member id (fluid-ref *prefixes*)) (if (not (module-defined? (current-module) '__prefixes__)) #f (let ((p (module-ref (current-module) '__prefixes__))) (member id (fluid-ref p)))))) (define-syntax call (syntax-rules () ((_ (f) . l) (f . l)))) (define (fold f init l) (if (pair? l) (fold f (f (car l) init) (cdr l)) init)) (define (pr . x) (define port (open-file "/home/stis/src/python-on-guile/log.txt" "a")) (with-output-to-port port (lambda () (pretty-print (syntax->datum x)))) (close port) (car (reverse x))) (define (pf x) (define port (open-file "/home/stis/src/python-on-guile/compile.log" "a")) (with-output-to-port port (lambda () (pretty-print (syntax->datum x)) x)) (close port) x) (define (pp x) (pretty-print (syntax->datum x)) x) (define (gen-sel vs e item) (match e (#f item) ((#:cfor for-e in-e cont) `(,(F 'for) ((,@(map (g vs exp) for-e) : ,(exp vs in-e))) () ,(gen-sel vs cont item))) ((#:cif cif cont) `(if ,(exp vs cif) ,(gen-sel vs cont item))))) (define (union as vs) (let lp ((as as) (vs vs)) (match as ((x . as) (if (member x vs) (lp as vs) (lp as (cons x vs)))) (() vs)))) (define (diff as vs) (let lp ((as as) (rs '())) (match as ((x . as) (if (member x vs) (lp as rs) (lp as (cons x rs)))) (() rs)))) (define (get-globals code) (let lp ((vs (glob code '())) (rs (scope code '()))) (match vs ((x . l) (if (member x rs) (lp l rs) (lp l (cons x rs)))) (() rs)))) (define (glob x vs) (match x ((#:global . l) (let lp ((l l) (vs vs)) (match l (((#:identifier v . _) . l) (let ((s (string->symbol v))) (if (member s vs) (lp l vs) (lp l (cons s vs))))) (() vs)))) ((x . y) (glob y (glob x vs))) (x vs))) (define (scope x vs) (match x ((#:def f . _) (union (list (exp '() f)) vs)) ((#:lambdef . _) vs) ((#:classdef f . _) (union (list (exp '() f)) vs)) ((#:global . _) vs) ((#:expr-stmt l (#:assign u)) (union (fold (lambda (x s) (match x ((#:test (#:power v2 v1 () . _) . _) (if v2 (union (union (list (exp '() v1)) (list (exp '() v2))) s) (union (list (exp '() v1)) s))) (_ s))) '() l) vs)) ((x . y) (scope y (scope x vs))) (_ vs))) (define (defs x vs) (match x ((#:def (#:identifier f) . _) (union (list (string->symbol f)) vs)) ((#:lambdef . _) vs) ((#:class . _) vs) ((#:global . _) vs) ((x . y) (defs y (defs x vs))) (_ vs))) (define (gen-yield f) (string->symbol (string-append (symbol->string f) ".yield"))) (define (g vs e) (lambda (x) (e vs x))) (define return (make-fluid 'error-return)) (define-syntax-rule (<< x y) (ash x y)) (define-syntax-rule (>> x y) (ash x (- y))) (define-syntax-rule (mkfast ((a) v) ...) (let ((h (make-hash-table))) (hash-set! h 'a v) ... h)) (define (fast-ref x) (aif it (assoc x `((__class__ . ,(O 'py-class)))) (cdr it) #f)) (define fasthash (mkfast ;; General ((__init__) (O 'init)) ((__getattr__) (O 'getattr)) ((__setattr__) (O 'setattr)) ((__delattr__) (O 'delattr)) ((__ne__) (O 'ne)) ((__eq__) (O 'equal?)) ((__repr__) (O 'repr)) ;;iterators ((__iter__) (F 'wrap-in)) ((__next__) (F 'next)) ((__send__) (Y 'send)) ((__exception__) (Y 'sendException)) ((__close__) (Y 'sendClose)) ;; Numerics ((__add__ ) (N '+)) ((__mul__ ) (N '*)) ((__sub__ ) (N '-)) ((__radd__ ) (N 'r+)) ((__rmul__ ) (N 'r*)) ((__rsub__ ) (N 'r-)) ((__neg__ ) (N '-)) ((__le__ ) (N '<)) ((__lt__ ) (N '<=)) ((__ge__ ) (N '>)) ((__gt__ ) (N '>=)) ((__abs__ ) (N 'py-abs)) ((__pow__ ) (N 'expt)) ((__rpow__ ) (N 'rexpt)) ((__truediv__) (N 'py-/)) ((__rtruediv__) (N 'py-r/)) ((__and__) (N 'py-logand)) ((__or__) (N 'py-logior)) ((__xor__) (N 'py-logxor)) ((__rand__) (N 'py-rlogand)) ((__ror__) (N 'py-rlogior)) ((__rxor__) (N 'py-rlogxor)) ((__divmod__) (N 'py-divmod)) ((__rdivmod__) (N 'py-rdivmod)) ((__invert__) (N 'py-lognot)) ((__int__) (N 'mk-int)) ((__float__) (N 'mk-float)) ;; Lists ((append) (L 'pylist-append!)) ((count) (L 'pylist-count)) ((extend) (L 'pylist-extend!)) ((index) (L 'pylist-index)) ((pop) (L 'pylist-pop!)) ((insert) (L 'pylist-insert!)) ((remove) (L 'pylist-remove!)) ((reverse) (L 'pylist-reverse!)) ((sort) (L 'pylist-sort!)) ((__len__) (L 'len)) ((__contains__) (L 'in)) ((__delitem__) (L 'pylist-delete!)) ((__delslice__) (L 'pylist-delslice)) ((__setitem__) (L 'pylist-set!)) ;; String ((format) (S 'py-format )) ((capitalize) (S 'py-capitalize)) ((center) (S 'py-center )) ((endswith) (S 'py-endswith)) ((expandtabs) (S 'py-expandtabs)) ((find) (S 'py-find )) ((rfind) (S 'py-rfind )) ((isalnum) (S 'py-isalnum)) ((isalpha) (S 'py-isalpha)) ((isdigit) (S 'py-isdigit)) ((islower) (S 'py-islower)) ((isspace) (S 'py-isspace)) ((isupper) (S 'py-isupper)) ((istitle) (S 'py-istitle)) ((join) (S 'py-join )) ((ljust) (S 'py-join )) ((rljust) (S 'py-rljust )) ((lower) (S 'py-lower )) ((upper) (S 'py-upper )) ((lstrip) (S 'py-lstrip )) ((rstrip) (S 'py-rstrip )) ((partition) (S 'py-partiti)) ((replace) (S 'py-replace)) ((strip) (S 'py-strip )) ((title) (S 'py-title )) ((rpartition) (S 'py-rpartition)) ((rindex) (S 'py-rindex )) ((split) (S 'py-split )) ((rsplit) (S 'py-rsplit )) ((splitlines) (S 'py-splitlines)) ((startswith) (S 'py-startswith)) ((swapcase) (S 'py-swapcase)) ((translate) (S 'py-translate)) ((zfill) (S 'py-zfill)) ;;DICTS ((copy) (Di 'py-copy)) ((fromkeys) (Di 'py-fromkeys)) ((get) (Di 'py-get)) ((has_key) (Di 'py-has_key)) ((items) (Di 'py-items)) ((iteritems) (Di 'py-iteritems)) ((iterkeys) (Di 'py-iterkeys)) ((itervalues) (Di 'py-itervalues)) ((keys) (Di 'py-keys)) ((values) (Di 'py-values)) ((popitem) (Di 'py-popitem)) ((setdefault) (Di 'py-setdefault)) ((update) (Di 'py-update)) ((clear) (Di 'py-clear)) ((__hash__) (H 'py-hash)))) (define (fastfkn x) (hash-ref fasthash x)) (define (get-kwarg vs arg) (let lp ((arg arg) (l '()) (kw '())) (match arg (((#:= a b) . arg) (lp arg l (cons* (exp vs b) (symbol->keyword (exp vs a)) kw))) ((x . arg) (lp arg (cons (exp vs x) l) kw)) (() (values (reverse l) (reverse kw)))))) (define (get-kwarg-def vs arg) (let lp ((arg arg)) (match arg ((((x . _) #f) . arg) (cons (exp vs x) (lp arg))) ((((a . _) b) . arg) (cons (list '= (exp vs a) (exp vs b)) (lp arg))) (() '())))) (define (get-addings vs x) (match x (() '()) ((x . l) (let ((is-fkn? (match l ((#f) #t) (((#:arglist . _) . _) #t) (_ #f)))) (cons (match x ((#:identifier . _) (let* ((tag (exp vs x)) (xs (gensym "xs")) (fast (fastfkn tag)) (is-fkn? (aif it (and is-fkn? fast) `(#:call-obj (lambda (e) `(lambda ,xs (apply ,it ,e ,xs)))) #f))) (if is-fkn? is-fkn? (if fast `(#:fastfkn-ref ,fast ',tag) (aif it (fast-ref tag) `(#:fast-id ,it ',tag) `(#:identifier ',tag)))))) ((#:arglist args apply #f) (call-with-values (lambda () (get-kwarg vs args)) (lambda (args kwarg) (if apply `(#:apply ,@args ,@kwarg ,`(,(L 'to-list) ,(exp vs apply))) `(#:call ,@args ,@kwarg))))) ((#:subscripts (n #f #f)) `(#:vecref ,(exp vs n))) ((#:subscripts (n1 n2 n3)) (let ((w (lambda (x) (if (eq? x None) (E 'None) x)))) `(#:vecsub ,(w (exp vs n1)) ,(w (exp vs n2)) ,(w (exp vs n3))))) ((#:subscripts (n #f #f) ...) `(#:array-ref ,@ (map (lambda (n) (exp vs n)) n))) ((#:subscripts (n1 n2 n3) ...) (let ((w (lambda (x) (if (eq? x None) (E 'None) x)))) `(#:arraysub ,@(map (lambda (x y z) `(,(exp vs x) ,(exp vs y) ,(exp vs z))) n1 n2 n3)))) (_ (error "unhandled addings"))) (get-addings vs l)))))) (define (make-set vs op x u) (define (tr-op op) (match op ("+=" '+) ("-=" '-) ("*=" '*) ("/=" '/) ("%=" 'modulo) ("&=" 'logand) ("|=" 'logior) ("^=" 'logxor) ("**=" 'expt) ("<<=" (C '<<)) (">>=" (C '>>)) ("//=" 'floor-quotient))) (match x ((#:test (#:power kind v addings . _) . _) (let* ((v (exp vs v)) (v.add (if (is-prefix? v) (let ((w (symbol->string (exp vs (car addings))))) (cons (string-append (symbol->string v) "." w) (cdr addings))) (cons v addings))) (v (car v.add)) (addings (cdr v.add)) (addings (get-addings vs addings))) (define q (lambda (x) `',x)) (if kind (if (null? addings) (if op `(,s/d ,v (,(tr-op op) ,v ,u)) `(,s/d ,v ,u)) (if op `(,s/d ,(exp vs kind) (,(O 'fset-x) ,v (list ,@(map q addings)) (,(tr-op op) (,(C 'ref-x) ,v ,@addings) ,u))) `(,s/d ,(exp vs kind) (,(O 'fset-x) ,v (list ,@(map q addings)) ,u)))) (if (null? addings) (if op `(,s/d ,v (,(tr-op op) (,(C 'ref-x) ,v ,@addings) ,u)) `(,s/d ,v ,u)) `(,(C 'set-x) ,v ,addings ,(if op `(,(tr-op op) (,(C 'ref-x) ,v ,@addings) ,u) u)))))))) (define is-class? (make-fluid #f)) (define (gen-yargs vs x) (match (pr 'yarg x) ((#:list args) (map (g vs exp) args)))) (define inhibit-finally #f) (define tagis (make-hash-table)) (define-syntax-rule (gen-table x vs (tag code ...) ...) (begin (hash-set! tagis tag (lambda (x vs) (match x code ...))) ...)) (gen-table x vs (#:power ((_ _ (x) () . #f) (exp vs x)) ((_ _ x () . #f) (exp vs x)) ((_ #f vf trailer . **) (let* ((vf (exp vs vf)) (vf.tr (if (is-prefix? vf) (cons (string->symbol (string-append (symbol->string vf) "." (symbol->string (exp vs (car trailer))))) (cdr trailer)) (cons vf trailer))) (vf (car vf.tr)) (trailer (cdr vf.tr))) (define (pw x) (if ** `(expt ,x ,(exp vs **)) x)) (pw (let ((trailer (get-addings vs trailer))) `(,(C 'ref-x) ,vf ,@trailer)))))) (#:identifier ((#:identifier x . _) (string->symbol x))) (#:string ((#:string #f x) x)) (#:+ ((_ . l) (cons '+ (map (g vs exp) l)))) (#:- ((_ . l) (cons '- (map (g vs exp) l)))) (#:* ((_ . l) (cons '* (map (g vs exp) l)))) (#:/ ((_ . l) (cons (N 'py-/) (map (g vs exp) l)))) (#:% ((_ . l) (cons 'modulo (map (g vs exp) l)))) (#:// ((_ . l) (cons 'floor-quotient (map (g vs exp) l)))) (#:<< ((_ . l) (cons (C '<<) (map (g vs exp) l)))) (#:>> ((_ . l) (cons (C '>>) (map (g vs exp) l)))) (#:u~ ((_ x) (list 'lognot (exp vs x)))) (#:u- ((_ x) (list '- (exp vs x)))) (#:u+ ((_ x) (list '+ (exp vs x)))) (#:band ((_ . l) (cons 'logand (map (g vs exp) l)))) (#:bxor ((_ . l) (cons 'logxor (map (g vs exp) l)))) (#:bor ((_ . l) (cons 'logior (map (g vs exp) l)))) (#:not ((_ x) (list 'not (exp vs x)))) (#:or ((_ . x) (cons 'or (map (g vs exp) x)))) (#:and ((_ . x) (cons 'and (map (g vs exp) x)))) (#:test ((_ e1 #f) (exp vs e1)) ((_ e1 e2 e3) (list 'if (exp vs e2) (exp vs e1) (exp vs e3)))) (#:del ;;We don't delete variables ((_ (#:power #f base () . #f)) '(void)) ((_ (#:power #f base (l ... fin) . #f)) (let ((add (get-addings vs l)) (fin (get-addings vs (list fin))) (f (exp vs base))) `(,(C 'del-x) (,(C 'ref-x) ,f ,@add) ,@fin)))) (#:if ((_ test a ((tests . as) ...) . else) `(,(G 'cond) (,(exp vs test) ,(exp vs a)) ,@(map (lambda (p a) (list (exp vs p) (exp vs a))) tests as) ,@(if else `((else ,(exp vs else))) '())))) (#:suite ((_ . l) (cons 'begin (map (g vs exp) l)))) (#:classdef ((_ (#:identifier class . _) parents defs) (with-fluids ((is-class? #t)) (let () (define (filt l) (reverse (fold (lambda (x s) (match x ((or 'fast 'functional) s) (x (cons x s)))) '() l))) (define (is-functional l) (fold (lambda (x pred) (if pred pred (match x ('functional #t) (_ #f)))) #f l)) (define (is-fast l) (fold (lambda (x pred) (if pred pred (match x ('fast #t) (_ #f)))) #f l)) (let* ((class (string->symbol class)) (parents (match parents (() '()) (#f '()) ((#:arglist args . _) (map (g vs exp) args)))) (is-func (is-functional parents)) (is-fast (is-fast parents)) (kind (if is-func (if is-fast 'mk-pf-class 'mk-pyf-class) (if is-fast 'mk-p-class 'mk-py-class))) (parents (filt parents))) `(define ,class (,(O kind) ,class ,(map (lambda (x) `(,(O 'get-class) ,x)) parents) #:const () #:dynamic ,(match (exp vs defs) (('begin . l) l) ((('begin . l)) l) (l l))))))))) (#:scm ((_ (#:string _ s)) (with-input-from-string s read))) (#:import ((_ (#:from (() nm) . #f)) `(use-modules (language python module ,(exp vs nm)))) ((_ (#:name ((ids ...) . as) ...)) `(begin ,@(map (lambda (ids as) (let* ((syms (map (g vs exp) ids)) (id (if as (exp vs as) (car (reverse syms))))) (add-prefix id) `(use-modules ((language python module ,@syms) #:prefix ,(string->symbol (string-append (symbol->string id) ".")))))) ids as)))) (#:for ((_ e in code . #f) (=> next) (match e (((#:power #f (#:identifier x . _) () . #f)) (match in (((#:test power . _)) (match power ((#:power #f (#:identifier "range" . _) ((#:arglist arglist . _)) . _) (match arglist ((arg) (let ((v (gensym "v")) (x (string->symbol x)) (lp (gensym "lp"))) `(let ((,v ,(exp vs arg))) (let ,lp ((,x 0)) (if (< ,x ,v) (begin ,(exp vs code) (,lp (+ ,x 1)))))))) ((arg1 arg2) (let ((v1 (gensym "va")) (v2 (gensym "vb")) (lp (gensym "lp"))) `(let ((,v1 ,(exp vs arg1)) (,v2 ,(exp vs arg2))) (let ,lp ((,x ,v1)) (if (< ,x ,v2) (begin ,(exp vs code) (,lp (+ ,x 1)))))))) ((arg1 arg2 arg3) (let ((v1 (gensym "va")) (v2 (gensym "vb")) (st (gensym "vs")) (lp (gensym "lp"))) `(let ((,v1 ,(exp vs arg1)) (,st ,(exp vs arg2)) (,v2 ,(exp vs arg3))) (if (> st 0) (let ,lp ((,x ,v1)) (if (< ,x ,v2) (begin ,(exp vs code) (,lp (+ ,x ,st))))) (if (< st 0) (let ,lp ((,x ,v1)) (if (> ,x ,v2) (begin ,(exp vs code) (,lp (+ ,x ,st))))) (error "range with step 0 not allowed")))))) (_ (next)))) (_ (next)))) (_ (next)))) (_ (next)))) ((_ es in code . else) (let* ((es2 (map (g vs exp) es)) (vs2 (union es2 vs)) (code2 (exp vs2 code)) (p (is-ec #t code2 #t (list (C 'break) (C 'continue)))) (else2 (if else (exp vs2 else) #f)) (in2 (map (g vs exp) in))) (list (C 'for) es2 in2 code2 else2 p)))) (#:while ((_ test code . #f) (let ((lp (gensym "lp"))) `(let ,lp () (if ,(exp vs test) (begin ,(exp vs code) (,lp)))))) ((_ test code else) (let ((lp (gensym "lp"))) `(let ,lp () (if test (begin ,(exp vs code) (,lp)) ,(exp vs else)))))) (#:try ((_ x (or #f ()) #f . fin) (if fin `(,(T 'try) ,(exp vs x) #:finally (lambda () fin)) (exp vs x))) ((_ x exc else . fin) `(,(T 'try) ,(exp vs x) ,@(let lp ((exc exc) (r (if else (exp vs else) '()))) (match exc ((((test . #f) code) . exc) (lp exc (cons `(#:except ,(exp vs code)) r))) ((((test . as) code) . exc) (let ((l (gensym "l"))) (lp exc (cons `(#:except ,(exp vs test) => (lambda (,(exp vs as) . ,l) ,(exp vs code))) r)))) (() (reverse r)))) ,@(if fin `(#:finally (lambda () ,(exp vs fin))) '())))) (#:subexpr ((_ . l) (exp vs l))) (#:raise ((_ #f . #f) `(,(T 'raise) (,(O 'Exception)))) ((_ code . #f) `(,(T 'raise) ,(exp vs code))) ((_ code . from) (let ((o (gensym "o")) (c (gensym "c"))) `(,(T 'raise) (let ((,c ,(exp vs code))) (let ((,o (if (,(O 'pyclass?) ,c) (,c) ,c))) (,(O 'set) ,o '__cause__ ,(exp vs from)) ,o)))))) (#:yield ((_ args) (let ((f (gensym "f"))) `(begin (fluid-set! ,(Y 'in-yield) #t) (let ((,f (scm.yield ,@(gen-yargs vs args)))) (,f))))) ((_ f args) (let ((f (gen-yield (exp vs f))) (g (gensym "f"))) `(begin (set! ,(C 'inhibit-finally) #t) (let ((,g (,f ,@(gen-yargs vs args)))) (,g)))))) (#:def ((_ f (#:types-args-list args *e **e) #f code) (let* ((args (get-kwarg-def vs args)) (c? (fluid-ref is-class?)) (f (exp vs f)) (y? (is-yield f #f code)) (r (gensym "return")) (*f (match *e (((e . #f) ()) (list (list '* (exp vs e)))) (#f '()))) (dd2 (match *e (((e . #f) ()) (list (exp vs e))) (#f '()))) (**f (match **e ((e . #f) (list (list '** (exp vs e)))) (#f '()))) (dd3 (match **e ((e . #f) (list (exp vs e))) (#f '()))) (as (map (lambda (x) (match x (('= a _) a) (a a))) args)) (ab (gensym "ab")) (vs (union dd3 (union dd2 (union as vs)))) (ns (scope code vs)) (df (defs code '())) (ex (gensym "ex")) (y 'scm.yield) (y.f (gen-yield f)) (ls (diff (diff ns vs) df))) (define (mk code) `(let-syntax ((,y (syntax-rules () ((_ . args) (abort-to-prompt ,ab . args)))) (,y.f (syntax-rules () ((_ . args) (abort-to-prompt ,ab . args))))) ,code)) (with-fluids ((is-class? #f)) (if c? (if y? `(define ,f (,(C 'def-wrap) ,y? ,f ,ab (,(D 'lam) (,@args ,@*f ,@**f) (,(C 'with-return) ,r ,(mk `(let ,(map (lambda (x) (list x #f)) ls) ,(with-fluids ((return r)) (exp ns code)))))))) `(define ,f (,(D 'lam) (,@args ,@*f ,@**f) (,(C 'with-return) ,r ,(mk `(let ,(map (lambda (x) (list x #f)) ls) ,(with-fluids ((return r)) (exp ns code)))))))) (if y? `(define ,f (,(C 'def-wrap) ,y? ,f ,ab (,(D 'lam) (,@args ,@*f ,@**f) (,(C 'with-return) ,r (let ,(map (lambda (x) (list x #f)) ls) ,(with-fluids ((return r)) (mk (exp ns code)))))))) `(define ,f (,(D 'lam) (,@args ,@*f ,@**f) (,(C 'with-return) ,r (let ,(map (lambda (x) (list x #f)) ls) ,(with-fluids ((return r)) (exp ns code)))))))))))) (#:global ((_ . _) '(values))) (#:list ((_ x (and e (#:cfor . _))) (let ((l (gensym "l"))) `(let ((,l (,(L 'to-pylist) '()))) ,(gen-sel vs e `(,(L 'pylist-append!) ,l ,(exp vs x))) ,l))) ((_ . l) (list (L 'to-pylist) (let lp ((l l)) (match l ((or () #f) ''()) (((#:starexpr #:power #f (#:list . l) . _) . _) (lp l)) (((#:starexpr #:power #f (#:tuple . l) . _) . _) (lp l)) (((#:starexpr . l) . _) `(,(L 'to-list) ,(exp vs l))) ((x . l) `(cons ,(exp vs x) ,(lp l)))))))) (#:tuple ((_ x (and e (#:cfor . _))) (let ((l (gensym "l"))) `(let ((,l '())) ,(gen-sel vs e `(set! ,l (cons ,(exp vs x) ,l))) (reverse ,l)))) ((_ . l) (let lp ((l l)) (match l (() ''()) (((#:starexpr #:power #f (#:list . l) . _) . _) (lp l)) (((#:starexpr #:power #f (#:tuple . l) . _) . _) (lp l)) (((#:starexpr . l) . _) `(,(L 'to-list) ,(exp vs l))) ((x . l) `(cons ,(exp vs x) ,(lp l))))))) (#:lambdef ((_ v e) (list `lambda v (exp vs e)))) (#:stmt ((_ l) (if (> (length l) 1) (cons 'values (map (g vs exp) l)) (exp vs (car l))))) (#:expr-stmt ((_ (l) (#:assign)) (exp vs l)) ((_ l type) (=> fail) (call-with-values (lambda () (match type ((#:assign u) (values #f u)) ((#:augassign op u) (values op u)) (_ (fail)))) (lambda (op u) (cond ((= (length l) (length u)) (if (= (length l) 1) (make-set vs op (car l) (exp vs (car u))) (cons 'begin (map (lambda (l u) (make-set vs op l u)) l (map (g vs exp) u))))) ((and (= (length u) 1) (not op)) (let ((vars (map (lambda (x) (gensym "v")) l))) `(call-with-values (lambda () (exp vs (car u))) (lambda vars ,@(map (lambda (l v) (make-set vs op l v)) l vars))))))))) ((_ ((#:test (#:power #f (#:identifier v . _) () . #f) #f)) (#:assign (l))) (let ((s (string->symbol v))) `(,s/d ,s ,(exp vs l))))) (#:return ((_ . x) `(,(fluid-ref return) ,@(map (g vs exp) x)))) (#:dict ((_ . #f) `(,(Di 'make-py-hashtable))) ((_ (#:e k . v) (and e (#:cfor . _))) (let ((dict (gensym "dict"))) `(let ((,dict (,(Di 'make-py-hashtable)))) ,(gen-sel vs e `(,(L 'pylist-set!) ,dict ,(exp vs k) ,(exp vs v))) ,dict))) ((_ (#:e k . v) ...) (let ((dict (gensym "dict"))) `(let ((,dict (,(Di 'make-py-hashtable)))) ,@(map (lambda (k v) `(,(L 'pylist-set!) ,dict ,(exp vs k) ,(exp vs v))) k v) ,dict))) ((_ k (and e (#:cfor . _))) (let ((dict (gensym "dict"))) `(let ((,dict (,(Se 'set)))) ,(gen-sel vs e `((,(O 'ref) ,dict 'add) ,(exp vs k))) ,dict))) ((_ k ...) (let ((set (gensym "dict"))) `(let ((,set (,(Se 'set)))) ,@(map (lambda (k) `((,(O 'ref) ,set 'add) ,(exp vs k))) k) ,set)))) (#:comp ((_ x #f) (exp vs x)) ((_ x (op . y)) (define (tr op x y) (match op ((or "<" ">" "<=" ">=") (list (G (string->symbol op)) x y)) ("!=" (list (G 'not) (list (G 'equal?) x y))) ("==" (list (G 'equal?) x y)) ("is" (list (G 'eq?) x y)) ("isnot" (list (G 'not) (list (G 'eq?) x y))) ("in" (list (L 'in) x y)) ("notin" (list (G 'not) (list (L 'in) x y))) ("<>" (list (G 'not) (list (G 'equal?) x y))))) (tr op (exp vs x) (exp vs y))))) (define (exp vs x) (match (pr x) ((e) (exp vs e)) ((tag . l) ((hash-ref tagis tag (lambda y (warn "not tag in tagis") x)) x vs)) (#:True #t) (#:None (E 'None)) (#:null ''()) (#:False #f) (#:pass `(values)) (#:break (C 'break)) (#:continue (C 'continue)) (x x))) (define (comp x) (define start (match (pr 'start x) (((#:stmt ((#:expr-stmt ((#:test (#:power #f (#:identifier "module" . _) ((#:arglist arglist #f #f)) . #f) #f)) (#:assign)))) . _) (let () (define args (map (lambda (x) (exp '() x)) arglist)) `((,(G 'define-module) (language python module ,@args) #:use-module (language python module python))))) (x '()))) (if (fluid-ref (@@ (system base compile) %in-compile)) (with-fluids ((*prefixes* '())) (if (fluid-ref (@@ (system base compile) %in-compile)) (set! s/d 'set!) (set! s/d 'define)) (if (pair? start) (set! x (cdr x))) (let ((globs (get-globals x))) `(begin ,@start ,(C 'clear-warning-data) (set! (@@ (system base message) %dont-warn-list) '()) ,@(map (lambda (s) `(,(C 'var) ,s)) globs) ,@(map (g globs exp) x)))) (begin (if (fluid-ref (@@ (system base compile) %in-compile)) (set! s/d 'set!) (set! s/d 'define)) (if (pair? start) (set! x (cdr x))) (let ((globs (get-globals x))) `(begin ,@start ,(C 'clear-warning-data) (set! (@@ (system base message) %dont-warn-list) '()) ,@(map (lambda (s) `(,(C 'var) ,s)) globs) ,@(map (g globs exp) x)))))) (define-syntax-parameter break (lambda (x) #'(values))) (define-syntax-parameter continue (lambda (x) (error "continue must be bound"))) (define (is-yield f p x) (match x ((#:def nm args _ code) (is-yield f #t code)) ((#:yield x _) (eq? f (exp '() x))) ((#:yield _) (not p)) ((a . l) (or (is-yield f p a) (is-yield f p l))) (_ #f))) (define-syntax-rule (with-sp ((x v) ...) code ...) (syntax-parameterize ((x (lambda (y) #'v)) ...) code ...)) (define (is-ec ret x tail tags) (syntax-case (pr 'is-ec x) (begin let if define @@) ((begin a ... b) #t (or (or-map (lambda (x) (is-ec ret x #f tags)) #'(a ...)) (is-ec ret #'b tail tags))) ((let lp ((y x) ...) a ... b) (symbol? (syntax->datum #'lp)) (or (or-map (lambda (x) (is-ec ret x #f tags)) #'(x ...)) (or-map (lambda (x) (is-ec ret x #f tags)) #'(a ...)) (is-ec ret #'b tail tags))) ((let ((y x) ...) a ... b) #t (or (or-map (lambda (x) (is-ec ret x #f tags)) #'(x ...)) (or-map (lambda (x) (is-ec ret x #f tags)) #'(a ...)) (is-ec ret #'b tail tags))) ((if p a b) #t (or (is-ec ret #'p #f tags) (is-ec ret #'a tail tags) (is-ec ret #'b tail tags))) ((define . _) #t #f) ((if p a) #t (or (is-ec ret #'p #f tags) (is-ec ret #'a tail tags))) ((@@ _ _) #t (if (member (pr (syntax->datum x)) tags) #t #f)) ((a ...) #t (or-map (lambda (x) (is-ec ret x #f tags)) #'(a ...))) (x #t #f))) (define-syntax with-return (lambda (x) (define (analyze ret x) (syntax-case x (begin let if) ((begin a ... b) #`(begin a ... #,(analyze ret #'b))) ((let lp v a ... b) (symbol? (syntax->datum #'lp)) #`(let lp v a ... #,(analyze ret #'b))) ((let v a ... b) #`(let v a ... #,(analyze ret #'b))) ((if p a b) #`(if p #,(analyze ret #'a) #,(analyze ret #'b))) ((if p a) #`(if p #,(analyze ret #'a))) ((return a b ...) (equal? (syntax->datum #'return) (syntax->datum ret)) (if (eq? #'(b ...) '()) #'a #`(values a b ...))) (x #'x))) (define (is-ec ret x tail) (syntax-case x (begin let if define @@) ((begin a ... b) #t (or (or-map (lambda (x) (is-ec ret x #f)) #'(a ...)) (is-ec ret #'b tail))) ((let lp ((y x) ...) a ... b) (symbol? (syntax->datum #'lp)) (or (or-map (lambda (x) (is-ec ret x #f)) #'(x ...)) (or-map (lambda (x) (is-ec ret x #f)) #'(a ...)) (is-ec ret #'b tail))) ((let ((y x) ...) a ... b) #t (or (or-map (lambda (x) (is-ec ret x #f)) #'(x ...)) (or-map (lambda (x) (is-ec ret x #f)) #'(a ...)) (is-ec ret #'b tail))) ((define . _) #t #f) ((if p a b) #t (or (is-ec ret #'p #f) (is-ec ret #'a tail) (is-ec ret #'b tail))) ((if p a) #t (or (is-ec ret #'p #f) (is-ec ret #'a tail))) ((return a b ...) (equal? (syntax->datum #'return) (syntax->datum ret)) (not tail)) ((a ...) #t (or-map (lambda (x) (is-ec ret x #f)) #'(a ...))) (x #t #f))) (syntax-case x () ((_ ret l) (let ((code (analyze #'ret #'l))) (if (is-ec #'ret #'l #t) #`(let/ec ret #,code) code)))))) (define-syntax var (lambda (x) (syntax-case x () ((_ v) (begin (dont-warn (syntax->datum #'v)) #'(if (module-defined? (current-module) 'v) (values) (define! 'v #f))))))) (define-inlinable (non? x) (eq? x #:nil)) (define (gentemp stx) (datum->syntax stx (gensym "x"))) (define-syntax for (syntax-rules () ((_ (x) (a) code #f #f) (if (pair? a) (let lp ((l a)) (if (pair? l) (let ((x (car l))) (with-sp ((continue (lp (cdr l))) (break (values))) code (lp (cdr l)))))) (for/adv1 (x) (a) code #f #f))) ((_ (x) (a) code #f #t) (if (pair? a) (let/ec break-ret (let lp ((l a)) (if (pair? l) (begin (let/ec continue-ret (let ((x (car l))) (with-sp ((continue (continue-ret)) (break (break-ret))) code))) (lp (cdr l)))))) (for/adv1 (x) (a) code #f #t))) ((_ (x) (a) code next #f) (if (pair? a) (let/ec break-ret (let ((x (let lp ((l a) (old #f)) (if (pair? l) (let ((x (car l))) (let/ec continue-ret (with-sp ((continue (continue-ret)) (break (break-ret))) code)) (lp (cdr l))) old)))) next)) (for/adv1 (x) (a) code next #f))) ((_ x a code next p) (for/adv1 x a code next p)))) (define-syntax for/adv1 (lambda (x) (syntax-case x () ((_ (x ...) (in) code #f #f) (with-syntax ((inv (gentemp #'in))) #'(let ((inv (wrap-in in))) (catch StopIteration (lambda () (let lp () (call-with-values (lambda () (next inv)) (lambda (x ...) (with-sp ((break (values)) (continue (values))) code (lp)))))) (lambda z (values)))))) ((_ (x ...) (in ...) code #f #f) (with-syntax (((inv ...) (generate-temporaries #'(in ...)))) #'(let ((inv (wrap-in in)) ...) (catch StopIteration (lambda () (let lp () (call-with-values (lambda () (values (next inv) ...)) (lambda (x ...) (with-sp ((break (values)) (continue (values))) code (lp)))))) (lambda z (values)))))) ((_ (x ...) (in) code #f #t) (with-syntax ((inv (gentemp #'in))) #'(let ((inv (wrap-in in))) (let lp () (let/ec break-ret (catch StopIteration (lambda () (call-with-values (lambda () (next inv)) (lambda (x ...) (let/ec continue-ret (with-sp ((break (break-ret)) (continue (continue-ret))) code)) (lp)))) (lambda z (values)))))))) ((_ (x ...) (in ...) code #f #t) (with-syntax (((inv ...) (generate-temporaries #'(in ...)))) #'(let ((inv (wrap-in in)) ...) (let lp () (let/ec break-ret (catch StopIteration (lambda () (call-with-values (lambda () (values (next inv) ...)) (lambda (x ...) (let/ec continue-ret (with-sp ((break (break-ret)) (continue (continue-ret))) code)) (lp)))) (lambda z (values)))))))) ((_ (x ...) in code else #f) #'(for-adv (x ...) in code else #f)) ((_ (x ...) in code else #t) #'(for-adv (x ...) in code else #t))))) (define-syntax for-adv (lambda (x) (define (gen x y) (if (= (length (syntax->datum x)) (= (length (syntax->datum y)))) (syntax-case x () ((x ...) #'(values (next x) ...))) (syntax-case x () ((x) #'(next x))))) (syntax-case x () ((_ (x ...) (in) code else p) (with-syntax ((inv (gentemp #'in))) (with-syntax (((xx ...) (generate-temporaries #'(x ...)))) (if (syntax->datum #'p) #'(let ((inv (wrap-in in))) (let/ec break-ret (let ((x #f) ...) (catch StopIteration (lambda () (let lp () (call-with-values (lambda () (next inv)) (lambda (xx ...) (set! x xx) ... (let/ec continue-ret (with-sp ((break (break-ret)) (continue (continue-ret))) code)) (lp))))) (lambda q else))))) #'(let ((inv (wrap-in in))) (let ((x #f) ...) (let/ec break-ret (catch StopIteration (lambda () (let lp () (call-with-values (lambda () (next inv)) (lambda (xx ...) (set! x xx) ... (with-sp ((break (break-ret)) (continue (values))) code) (lp))))) (lambda e else))))))))) ((_ (x ...) (in ...) code else p) (with-syntax (((inv ...) (generate-temporaries #'(in ...)))) (with-syntax ((get (gen #'(inv ...) #'(x ...))) ((xx ...) (generate-temporaries #'(x ...)))) (if (syntax->datum #'p) #'(let ((inv (wrap-in in)) ...) (let/ec break-ret (let ((x #f) ...) (catch StopIteration (lambda () (let lp () (call-with-values (lambda () get) (lambda (xx ...) (set! x xx) ... (let/ec continue-ret (with-sp ((break (break-ret)) (continue (continue-ret))) code)) (lp))))) (lambda q else))))) #'(let ((inv (wrap-in in)) ...) (let ((x #f) ...) (let/ec break-ret (catch StopIteration (lambda () (let lp () (call-with-values (lambda () get) (lambda (xx ...) (set! x xx) ... (with-sp ((break (break-ret)) (continue (values))) code) (lp))))) (lambda e else)))))))))))) (define-syntax def-wrap (lambda (x) (syntax-case x () ((_ #f f ab x) (pr 'def-wrap #'f 'false) #'x) ((_ #t f ab code) (pr 'def-wrap #'f 'true) #'(lambda x (define obj (make )) (define ab (make-prompt-tag)) (slot-set! obj 'k #f) (slot-set! obj 'closed #f) (slot-set! obj 's (lambda () (call-with-prompt ab (lambda () (let/ec return (apply code x)) (slot-set! obj 'closed #t) (throw StopIteration)) (letrec ((lam (lambda (k . l) (fluid-set! in-yield #f) (slot-set! obj 'k (lambda (a) (call-with-prompt ab (lambda () (k a)) lam))) (apply values l)))) lam)))) obj))))) (define-syntax ref-x (syntax-rules () ((_ v) v) ((_ v (#:fastfkn-ref f _) . l) (ref-x (lambda x (if (py-class? v) (apply f x) (apply f v x))) . l)) ((_ v (#:fast-id f _) . l) (ref-x (f v) . l)) ((_ v (#:identifier x) . l) (ref-x (refq v 'x) . l)) ((_ v (#:identifier x) . l) (ref-x (refq v 'x) . l)) ((_ v (#:call-obj x) . l) (ref-x (x v) . l)) ((_ v (#:call x ...) . l) (ref-x (v x ...) . l)) ((_ v (#:apply x ...) . l) (ref-x (apply v x ...) . l)) ((_ v (#:apply x ...) . l) (ref-x (apply v x ...) . l)) ((_ v (#:vecref x) . l) (ref-x (pylist-ref v x) . l)) ((_ v (#:vecsub . x) . l) (ref-x (pylist-slice v . x) . l)))) (define-syntax del-x (syntax-rules () ((_ v (#:identifier x)) (ref-x (refq v 'x))) ((_ v (#:call-obj x)) (values)) ((_ v (#:call x ...)) (values)) ((_ v (#:apply x ...)) (values)) ((_ v (#:vecref x)) (pylist-delete! v x)) ((_ v (#:vecsub x ...)) (pylist-subset! v x ... pylist-null)))) (define-syntax set-x (syntax-rules () ((_ v (a ... b) val) (set-x-2 (ref-x v a ...) b val)))) (define-syntax set-x-2 (syntax-rules () ((_ v (#:fastfkn-ref f id) val) (set v id val)) ((_ v (#:fastid-ref f id) val) (set v id val)) ((_ v (#:identifier x) val) (set v x val)) ((_ v (#:vecref n) val) (pylist-set! v n val)) ((_ v (#:vecsub x ...) val) (pylist-subset! v x ... val))))