b0VIM 7.3+N8iQasumucalcifer~asumu/software/readable/trunk/sweet/modern.rktutf-8 3210#"! UtpY`Z^^Gvad#Yd$ DB ~ @ : h H F  | P N ~ a ` _ ; X ~{1]<Y Y;:xeUE90/; Unfortunately, this seems to be the only portable way to define the; Define the tab character; a tab is immediately after the backslash. value) (newline) (write value) (display " ") (display marker) (display "DEBUG: ") (newline) ; after printing it returns the original value. ; For debugging - you can insert this without adding let, etc., because(define (debug-result marker value) (pair? (member item lyst))) ; Returns true if item is member of lyst, else false.(define (ismember? item lyst); A few useful utilities: ; if not, "f[...]" => [f ...].(define modern-bracketaccess #f) ; If true, "f[...]" => [bracketaccess f ...](define modern-backwards-compatible #f) ; If true, "(" triggers old reader.; Configuration:(export (rename read^ [modern-read read]))(import (prefix old- read^))(require "read-sig.rkt"); OTHER DEALINGS IN THE SOFTWARE.; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR; ; in all copies or substantial portions of the Software.; The above copyright notice and this permission notice shall be included; ; Software is furnished to do so, subject to the following conditions:; and/or sell copies of the Software, and to permit persons to whom the; the rights to use, copy, modify, merge, publish, distribute, sublicense,; to deal in the Software without restriction, including without limitation; copy of this software and associated documentation files (the "Software"),; Permission is hereby granted, free of charge, to any person obtaining a; Released under the "MIT license":; prefixed [] and {} at all.; must be PRECEDED by a delimiter like a space, and you CANNOT invoke; consider {} or [] as delimiters. But then closing characters } and ]; You _could_ in a pinch use a standard Scheme reader that didn't;; is to build this into your Scheme reader.; In code, just use vector(...) instead. The best solution, of course,; the vector notation #(...) could not contain modern notation.; If you DO use an ordinary Scheme reader, there is a limitation:;; this simple reader does not).; built-in "read" function (which probably has additional extensions that; you can eliminate all of that re-implementation code, and just use your; If your Scheme _does_ treat these characters as delimiters,; DOES treat them as delimiters. So a simple re-implemention is provided.; The only solution is to re-implement "read" in Scheme, but one that; at all, such as at the end of a number.; This is even true when the Scheme standards don't permit such characters; instead of treating them as delimiters like space, (, or ).; quirk: most Scheme implementations' "read" function CONSUMES [, ], {, and },; NOTE: This would be really easy to implement in Scheme, except for one;; Copyright (C) 2008 by David A. Wheeler.;; Call "modern-read" to read a "modern Lisp expression", aka mod-expression.;; x[z] => (bracketaccess x z); f{x + 3} => (f (+ x 3); f(x) => (f x); {3 + 4 + 5} => (+ 3 4 5); [x y z] => (x y z); These implement "curly infix" and term-prefixing rules. E.G.:; Implements "modern Lisp expressions", aka mod-expressions.;; NOTE: NOT READY FOR PRODUCTION USE.;; modern.scm (Scheme), 2008-01-03#lang racket/unitad#[GvV#|dI2 l Z - f I  z ] .  f K , y \ [ Z = *  xl.-[Z (load (open-input-file filename))) (load port))))) (eval inp) (begin #t (if (eof-object? inp) (let ((inp (modern-read port))) (define (load port)(define (modern-load filename) (begin (write result) (newline) (modern-filter))))) result (if (eof-object? result) (let ((result (modern-read (current-input-port))))(define (modern-filter) (modern-read2 (car port)))) (modern-read2 (current-input-port)) (if (null? port)(define (modern-read . port) result)))))) ; (printf "DEBUG peek after = ~a ~n" (peek-char port)) ; (printf "DEBUG result = ~a ~n" result) (#t (let ((result (underlying-read port))) (modern-read2 port)) (skip-line port) ((char=? c #\; ) ; Handle ";" directly, so we don't lose control. (my-read-delimited-list #\} port))) (process-curly (read-char port) ((char=? c #\{ ) (my-read-delimited-list #\] port)) (read-char port) ((char=? c #\[ ) (my-read-delimited-list #\) port)))) (read-char port) ; ( (begin (underlying-read port) (if modern-backwards-compatible ((char=? c #\( ) ; ) (modern-read2 port))))) (list 'unquote (#t (modern-read2 port))) (list 'unquote-splicing (read-char port) ((char=? #\@ (peek-char port)) (cond (read-char port) ((char=? c #\,) (modern-read2 port))) (list 'quasiquote (read-char port) ((char=? c #\`) (modern-read2 port))) (list 'quote (read-char port) ((char=? c #\') ((eof-object? c) eof) ; we retain control over the reading process. ; We need to directly implement abbreviations ', etc., so that (cond ; (printf "modern-read2 peeked at: ~a ~n" c) (let ((c (peek-char port))) (modern-process-tail port (skip-whitespace port) ; This implements unprefixed (), [], and {} ; Read using "modern Lisp notation".ad`iKCd L e d = q O  p V " !  J ) M9s)Ly,$q=|?>f\" (#t (read-number port (list #\.))) ; period digit - it's a number. ((ismember? c digits) ((eof-object? c) '|.|) ; period eof; return period. (cond (let ((c (peek-char port))) (read-char port) ; Remove . ; We've peeked a period character. Returns what it represents.(define (process-period port)(define digits '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)) (#t (read-error "Invalid #-prefixed string"))))))) ((char=? c #\\) (process-char port)) (list->vector (my-read-delimited-list #\) port))) ((char=? c #\( ) ; Vector. (read-number port (list #\# c))) ((ismember? c '(#\i #\e #\b #\o #\d #\x)) ((char=? c #\f) #f) ((char=? c #\t) #t) (cond (let ((c (read-char port))) ; Not EOF. Read in the next character, and start acting on it. (#t ((eof-object? (peek-char port)) (peek-char port)) ; If eof, return eof. (cond (read-char port) ; Remove # ; a vector expression. ; turn calls modern-read2. Thus, modern-expressions CAN be used inside ; the vector representation #(...) uses my-read-delimited-list, which in ; Note: Since we have to re-implement process-sharp anyway, ; We've peeked a # character. Returns what it represents.(define (process-sharp port) (#t (read-error "Invalid character name")))))))))) ((string-ci=? rest-string "tab") tab) ; Scheme extension. ((string-ci=? rest-string "ht") tab) ; Scheme extension. ((string-ci=? rest-string "newline") #\newline) ((string-ci=? rest-string "space") #\space) (cond (let ((rest-string (list->string (cons c rest)))) (#t ((null? rest) c) ; only one char after #\ - so that's it! (cond (rest (read-until-delim port modern-delimiters))) (let ((c (read-char port)) ; Not EOF. Read in the next character, and start acting on it. (#t ((eof-object? (peek-char port)) (peek-char port)) (cond ; We've read #\ - returns what it represents.(define (process-char port) (read-until-delim port modern-delimiters))))) (append starting-lyst (string->number (list->string(define (read-number port starting-lyst) '()) (display message) (display "Error: ")(define (read-error message) (#t (cons (read-char port) (read-until-delim port delims)))))) ((char-whitespace? c) '()) ((ismember? c delims) '()) ((eof-object? c) '()) (cond (let ((c (peek-char port))) ; Returns a list of chars. ; Read characters until eof or "delims" is seen; do not consume them.(define (read-until-delim port delims) `(#\space #\newline #\return #\( #\) #\[ #\] #\{ #\} ,tab))(define modern-delimiters; in common cases, and lets us use the implementation's string extensions).; We WILL call old-read on string reading (that DOES seem to work; with the limitation noted above about vector constants #(...).; you can just call old-read instead of using underlying-read below,; delimiters (and thus not consumed when reading symbols, numbers, etc.),; If you fix your Scheme's "read" so that [, {, }, and ] are considered; we have to re-implement our own Scheme reader. Ugh.; Unfortunately, since most Scheme readers will consume [, {, }, and ], (skip-whitespace port)])) (read-char port) [(and (char? c) (char-whitespace? c)) (cond (define c (peek-char port)) ; Consume whitespace.(define (skip-whitespace port)(define tab #\tab); tab character in Scheme, so we'll do it once (here) and use it elsewhere.ad!^Ui" g  <  d 4 < s Z E " wL-BpW7X='hgfed*)}8 >; Return True if the lyst is in simple infix format (and should be converted (#t (even-and-op-prefix op (cddr lyst))))) ; recurse. ((null? (cdr lyst)) #f) ; fail - odd # of parameters in lyst. ((not (eq? op (car lyst))) #f) ; fail - operators not all equal?. ((not (pair? lyst)) #f) ; Not a list. ((null? lyst) #t) (cond(define (even-and-op-prefix op lyst); If passed empty list, returns true (so recursion works correctly).; Otherwise it returns false.; ones are "op". Used to determine if a longer lyst is infix.; Return true if lyst has an even # of parameters, and the (alternating) first; Utility functions to implement the simple infix system:; End of Scheme reader re-implementation. (read-until-delim port modern-delimiters))))))) (string->symbol (list->string (#t ; Nothing else. Must be a symbol start. newsymbol)) (read-char port) (read-until-delim port '(#\|)))))) (string->symbol (list->string (let ((newsymbol (read-char port) ; Skip | ((char=? c #\| ) ; Scheme extension, |...| symbol (like Common Lisp) (underlying-read port)) (skip-line port) ((char=? c #\; ) (my-read-delimited-list #\) port)) (read-char port) ((char=? c #\( ) ; doesn't matter: ; be used anyway (modern-read will get first crack at it), it ; The "(" calls modern-read, but since this one shouldn't normally (underlying-read port))))) (list 'unquote (#t (underlying-read port))) (list 'unquote-splicing (read-char port) ((char=? #\@ (peek-char port)) (cond (read-char port) ((char=? c #\,) (underlying-read port))) (list 'quasiquote (read-char port) ((char=? c #\`) (underlying-read port))) (list 'quote (read-char port) ((char=? c #\') ; useful for other purposes. ; this function is a fully-usable Scheme reader, and thus perhaps ; and it makes some kinds of testing simpler. It also means that ; we won't see them), but redoing it here doesn't cost us anything, ; These actually should be done by modern-read (and thus ; We'll reimplement abbreviations, (, and ;. (read-until-delim port modern-delimiters)))))) (string->symbol (list->string (cons c (read-number port (list c)) (if (ismember? (peek-char port) digits) (read-char port) ((or (char=? c #\+) (char=? c #\-)) ; Initial + or - ((char=? c #\.) (process-period port)) ((char=? c #\#) (old-read port)) ; Racket's reader handles this (read-number port '())) ((ismember? c digits) ; Initial digit. (old-read port)) ; (guile 1.8 and gauche/gosh 1.8.11 are fine) ((char=? c #\") ; old readers tend to handle strings okay, call it. ((eof-object? c) c) (cond (let ((c (peek-char port))) (skip-whitespace port) ; _like_ case-sensitivity. ; and guile, but NOT with R5RS. Most people won't notice, and I ; Note: This reader is case-sensitive, which is consistent with R6RS ; won't forget to pass the port to it. ; That way, while writing/modifying it, we ; This tiny reader implementation REQUIRES a port value.(define (underlying-read port) (read-until-delim port modern-delimiters)))))))) (string->symbol (list->string (cons #\. ; As an extension we can support them all. ; At this point, Scheme only requires support for "." or "...".ad^r832 [ Z k j M - | 0 k R K 0 & U K  CBAm:sV-}V$~a; V8.(define (modern-read2 port) (skip-line port))))) (read-char port) ((not (or (eof-object? c) (char=? c #\newline))) (cond (let ((c (peek-char port))) ; Skip every character in the line - end on EOF or newline.(define (skip-line port) (#t prefix))))) (my-read-delimited-list #\} port))))) (process-curly (list prefix (modern-process-tail port (read-char port) ((char=? c #\{ ) ; Implement f{x} (cons prefix (my-read-delimited-list #\] port))))) (my-read-delimited-list #\] port))) (cons 'bracketaccess (cons prefix (if modern-bracketaccess (modern-process-tail port (read-char port) ((char=? c #\[ ) ; Implement f[x] (cons prefix (my-read-delimited-list #\) port)))) (modern-process-tail port ;( (read-char port) ((char=? c #\( ) ; ). Implement f(x). ((eof-object? c) c) (cond (let ((c (peek-char port))) prefix ; Prefixes MUST be symbol or cons; return original value. (if (not (or (symbol? prefix) (pair? prefix))) ; This implements prefixed (), [], and {} ; This recurses, to handle formats like f(x)(y). ; See if we've just finished reading a prefix, and if so, process.(define (modern-process-tail port prefix) (my-read-delimited-list stop-char port))))))))) (#t (cons datum datum2)))) (read-char port) (#t (read-error "Bad closing character after . datum")) ((not (eqv? (peek-char port) stop-char)) (cond (skip-whitespace port) (let ((datum2 (modern-read2 port))) ((eq? datum '|.|) (cond (let ((datum (modern-read2 port))) (#t ((ismember? c '(#\) #\] #\})) (read-error "Bad closing character") c) '()) ;( (read-char port) ((char=? c stop-char) ((eof-object? c) (read-error "EOF in middle of list") c) (cond ((c (peek-char port))) (let (skip-whitespace port) ; That could be important for I-expressions, e.g., (. group) ; This implements a common extension: (. b) return b. ; read the "inside" of a list until its matching stop-char, returning list. ; like read-delimited-list of Common Lisp, but calls modern-read instead.(define (my-read-delimited-list stop-char port) (cons 'nfx lyst))) ; Non-simple; prepend "nfx" to the list. (transform-simple-infix lyst) ; Simple infix expression. (if (simple-infix-listp lyst)(define (process-curly lyst) (cons (cadr lyst) (alternating-parameters lyst)))(define (transform-simple-infix lyst); followed by all the odd parameters. Thus (3 + 4 + 5) => (+ 3 4 5).; Transform a simple infix list - move the 2nd parameter into first position, (cons (car lyst) (alternating-parameters (cddr lyst))))) lyst (if (or (null? lyst) (null? (cdr lyst)))(define (alternating-parameters lyst); Return alternating parameters in a lyst (1st, 3rd, 5th, etc.) (even-and-op-prefix (cadr lyst) (cdr lyst)))) ; even parameters equal?? (symbol? (cadr lyst)) ; 2nd parameter must be a symbol. ; this way for performance) (pair? (cddr lyst)) ; Must have a third argument (we check it (pair? (cdr lyst)) ; Must have a second argument. (pair? lyst) ; Must have list; '() doesn't count. (and(define (simple-infix-listp lyst); at read time). Else returns NIL.