diff options
Diffstat (limited to 'modules/language/python/module/string.scm')
-rw-r--r-- | modules/language/python/module/string.scm | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/modules/language/python/module/string.scm b/modules/language/python/module/string.scm new file mode 100644 index 0000000..6ece062 --- /dev/null +++ b/modules/language/python/module/string.scm @@ -0,0 +1,278 @@ +(define-module (language python module string) + #:use-module (oop pf-objects) + #:use-module (oop goops) + #:use-module (ice-9 match) + #:use-module (language python number) + #:use-module ((language python module python) #:select (repr)) + #:use-module (language python exceptions) + #:use-module (language python yield) + #:use-module (language python list) + #:use-module (language python for) + #:use-module (language python def) + #:use-module (language python string) + #:use-module (parser stis-parser) + #:export (Formatter)) + +(define int (mk-token (f+ (f-reg! "[0-9]")) string->number)) +(define id (mk-token (f-seq (f-reg! "[_a-zA-Z]") + (f* (f-reg! "[_0-9a-zA-Z]"))))) +(define str (mk-token (f+ (f-not! (f-char #\[))))) + +(define conversion (mk-token (f-reg "[rsa]"))) + +(define fill (mk-token (f-reg! "."))) +(define align (mk-token (f-reg! "[<>=^]"))) +(define sign (mk-token (f-reg! "[-+ ]"))) +(define width int) +(define precision int) +(define type (mk-token (f-reg! "[bcdeEfFgGnosxX%]"))) +(define formatSpec + (f-list + (gg? (f-list #:align (gg? fill) align)) + (gg? sign) + (gg? (mk-token (f-tag! "#"))) + (gg? (mk-token (f-tag! "0"))) + (gg? width) + (gg? (mk-token (f-tag ","))) + (gg? (f-seq "." precision)) + (gg? type))) + +(define (get-align s align width sign) + (define widthq (- width (len sign))) + (define (f s a l) + (pk 'res (match (pk 'm a) + ("<" (apply py-ljust (+ sign s) width l)) + (">" (apply py-rjust (+ sign s) width l)) + ("^" (apply py-center (+ sign s) width l)) + ("=" (+ sign (apply py-rjust s widthq l)))))) + + (match align + (#f + (f s "<" '())) + ((_ #f a) + (f s a '())) + ((_ fill a) + (f s a (list fill))))) + +(define (convert-string s format-str) + (match (with-fluids ((*whitespace* f-true)) + (stis-parse format-str (f-seq formatSpec f-eof))) + ((align sign sharp zero width comma rec type) + (if width + (get-align s align width "") + s)))) + +(set! (@@ (language python string) format) convert-string) + +(define (gen-sign s sign) + (let lp ((sign sign)) + (match sign + (#f (lp "-")) + ("+" (if (< s 0) + (values (- s) "-") + (values s "+"))) + ("-" (if (< s 0) + (values (- s) "-") + (values s ""))) + (" " (if (< s 0) + (values (- s) "-") + (values s " ")))))) + +(define (convert-integer s format-str) + (match (pk 'conv-int + (with-fluids ((*whitespace* f-true)) + (stis-parse format-str (f-seq formatSpec f-eof)))) + ((align sign sharp zero width comma prec type) + (call-with-values (lambda () (gen-sign s sign)) + (lambda (s s-sign) + (let ((prefix (if sharp + (match type + ("b" "0b") + ("x" "0x") + ("X" "0X") + ("o" "0o") + ("d" "") + (#f "")) + "")) + (s (let lp ((type type)) + (match type + ("b" + (format #f "~b" s)) + ("x" + (format #f "~x" s)) + ("X" + (format #f "~:@(~x~)" s)) + ("o" + (format #f "~o" s)) + ("d" + (if comma + (format #f "~:d" s) + (format #f "~d" s))) + (#f + (lp "d")))))) + (if width + (if zero + (get-align s '(#:align "0" "=") width + (+ s-sign prefix)) + (get-align (+ prefix s) align width + s-sign)) + + (+ sign prefix s)))))))) + +(define-method (py-format (s <integer>) f) + (convert-integer s f)) + +(define-method (py-format (o <py-int>) f) + (convert-integer (slot-ref o 'x) f)) + +(define argName (f-or! id int)) +(define attributeName id) +(define elementIndex (f-or! int str)) + +(define fieldName + (f-cons argName (ff* (f-or! (f-list #:attr "." attributeName) + (f-list #:elem "[" elementIndex "]"))))) + +(define replField + (f-list + #:field + (ff? (mk-token (f-scope fieldName )) None) + (ff? (f-seq "!" (mk-token (f-scope conversion))) None) + (ff? (f-seq ":" (mk-token (f-scope formatSpec))) None))) + +(define tag (f-seq (f-tag "{") replField (f-tag "}"))) +(define nontag (f-list #:str + (mk-token (f+ (f-or! (f-tag! "{{") (f-not! tag)))))) +(define e (f-seq (ff* (f-or! tag nontag)) f-eof)) + +(define mk-gen + (make-generator (l) + (lambda (yield l) + (let lp ((u l) (i 0)) + (match (pk 'lp u) + (() + (yield "" None None None)) + (((#:str str)) + (yield str None None None)) + (((#:field a b c)) + (if (eq? a None) + (yield "" (number->string i) c b) + (yield "" a b c))) + (((#:field a b c) . u) + (if (eq? a None) + (begin + (yield "" (number->string i) c b) + (lp u (+ i 1))) + (begin + (yield "" a b c) + (lp u i)))) + (((#:str s) (#:field a b c) . u) + (if (eq? a None) + (begin + (yield s (number->string i) c b) + (pk 'next) + (lp u (+ i 1))) + (begin + (yield s a c b) + (lp u i))))))))) + +(define (f-parse str) + (let ((l (with-fluids ((*whitespace* f-true)) + (parse str e)))) + (mk-gen l))) + +(define stis-parse parse) + +(define-python-class Formatter () + (define format + (lam (self format_string (* args) (** kwargs)) + ((ref self 'vformat) format_string args kwargs))) + + (define vformat + (lambda (self format_string args kwargs) + (pk 'vformat format_string args kwargs) + (set self '_args '()) + (for ((s fn fo co : ((ref self 'parse) format_string))) ((ss '(""))) + (pk 'parse s ss fn fo co) + (if (eq? fn None) + (cons s ss) + (let* ((fn2 ((ref self 'get_field ) fn args kwargs)) + (fn3 (if (and (eq? fo None) (eq? co None)) + ((ref self 'convert_field) fn2 "r") + (let ((fn3 (if (eq? co None) + fn2 + ((ref self 'convert_field) + fn2 co)))) + (if (eq? fo None) + fn3 + ((ref self 'format_field ) + fn3 fo)))))) + (cons* fn3 s ss))) + #:final + (begin + ((ref self 'check_unused_args) (ref self '_args) args kwargs) + (apply string-append (reverse ss)))))) + + (define parse + (lambda (self format_string) + (f-parse format_string))) + + (define get_field + (lambda (self field_name args kwargs) + (pk 'get_field field_name args kwargs) + (match (pk 'field (with-fluids ((*whitespace* f-true)) + (stis-parse field_name fieldName))) + ((key a ...) + (set self '_args (cons key (ref self '_args))) + (let ((f ((ref self 'get_value) key args kwargs))) + (let lp ((a a) (f f)) + (match a + (((#:ref r) . l) + (lp l (ref f (string->symbol r)))) + (((#:elem k) . l) + (lp l (pylist-ref f k))) + (() + f))))) + (_ + (throw TypeError "wromg field name format"))))) + + (define get_value + (lambda (self key args kwargs) + (pk 'get_value key args kwargs) + (set self '__args (cons key args)) + (if (integer? key) + (pylist-ref args key) + (pylist-ref kwargs key)))) + + (define check_unused_args + (lambda (self used_args args kwargs) + (pk 'check_unused_args used_args args kwargs) + (let ((n (len args))) + (let lp ((i 0)) + (if (< i n) + (if (member i used_args) + (lp (+ i 1)) + (warn "unused arg" i))))) + (for ((k v : kwargs)) () + (pk 'key k) + (if (not (member k used_args)) + (warn "unused arg" k))))) + + + (define format_field + (lambda (self value format_spec) + (py-format value format_spec))) + + (define convert_field + (lambda (self value conversion) + (pk 'convert_field value conversion) + (cond + ((equal? conversion "s") + (str value)) + ((equal? conversion "r") + (repr value)) + ((equal? conversion "a") + (ascii value)) + (else + (throw TypeError "conversion" conversion)))))) + |