raco decompile: improve argument checking and reporting

Relevant to PR 14525
This commit is contained in:
Matthew Flatt 2014-05-27 06:34:19 +01:00
parent 9b42fca050
commit e4189afb15
2 changed files with 68 additions and 20 deletions

View File

@ -3,25 +3,80 @@
raco/command-name
compiler/zo-parse
compiler/decompile
racket/pretty)
racket/pretty
racket/format)
(define (get-name)
(string->symbol (short-program+command-name)))
(define force? #f)
(define source-files
(command-line
#:program (short-program+command-name)
#:once-each
[("--force") "Ignore timestamp mimatch on associated \".zo\""
(set! force? #t)]
[("--columns" "-n") n "Format for <n> columns"
(let ([num (string->number n)])
(unless (exact-positive-integer? num)
(raise-user-error (string->symbol (short-program+command-name))
(raise-user-error (get-name)
"not a valid column count: ~a" n))
(pretty-print-columns num))]
#:args source-or-bytecode-file
source-or-bytecode-file))
(define (check-files orig-file alt-file)
(cond
[(not (file-exists? alt-file))
(cond
[(file-exists? orig-file)
(unless (is-bytecode-file? orig-file)
(raise-user-error (get-name)
(~a "not a bytecode file, and no associated \".zo\" file\n"
" path: ~a\n"
" tried associated path: ~a")
orig-file
alt-file))]
[else
(raise-user-error (get-name)
(~a "no such file, and no associated \".zo\" file\n"
" path: ~a\n"
" tried associated path: ~a")
orig-file
alt-file)])]
[(not (is-bytecode-file? alt-file))
(raise-user-error (get-name)
(~a "associated \".zo\" file is not a bytecode file\n"
" original path: ~a\n"
" associated path: ~a")
orig-file
alt-file)]
[(and (not force?)
((file-or-directory-modify-seconds orig-file)
. > .
(file-or-directory-modify-seconds alt-file)))
;; return a warning:
(raise-user-error (get-name)
(~a "associated \".zo\" file's date is older than given file's date;\n"
" consider using `raco make` to rebuild the source file, or use `--force`\n"
" to skip the date check\n"
" original path: ~a\n"
" associated path: ~a")
orig-file
alt-file)]))
(define (is-bytecode-file? orig-file)
(call-with-input-file*
orig-file
(lambda (i)
(equal? #"#~" (read-bytes 2 i)))))
(for ([zo-file source-files])
(let ([zo-file (path->complete-path zo-file)])
(let-values ([(base name dir?) (split-path zo-file)])
(let ([alt-file (build-path base "compiled" (path-add-suffix name #".zo"))])
(check-files zo-file alt-file)
(parameterize ([current-load-relative-directory base]
[print-graph #t])
(pretty-write

View File

@ -9,13 +9,22 @@
@title[#:tag "decompile"]{@exec{raco decompile}: Decompiling Bytecode}
The @exec{raco decompile} command takes a bytecode file (which usually
The @exec{raco decompile} command takes the path of a bytecode file (which usually
has the file extension @filepath{.zo}) or a source file with an
associated bytecode file (usually created with @exec{raco make}) and
converts it back to an approximation of Racket code. Decompiled
converts the bytecode file's content back to an approximation of Racket code. Decompiled
bytecode is mostly useful for checking the compiler's transformation
and optimization of the source program.
The @exec{raco decompile} command accepts the following command-line flags:
@itemlist[
@item{@DFlag{force} --- skip modification-date comparison on the
given file's path and an associated @filepath{.zo} file (if any)}
@item{@Flag{n} @nonterm{n} or @DFlag{columns} @nonterm{n} --- format
output for a display with @nonterm{n} columns}
]
Many forms in the decompiled code, such as @racket[module],
@racket[define], and @racket[lambda], have the same meanings as
always. Other forms and transformations are specific to the rendering
@ -104,14 +113,6 @@ Many forms in the decompiled code, such as @racket[module],
of functions without an @racket['%%inline-variant%%] are never
inlined across modules.}
@item{Some applications of core primitives are annotated with
@racketidfont{#%in}, which indicates that the JIT compiler will
inline the operation. (Inlining information is not part of the
bytecode, but is instead based on an enumeration of primitives that
the JIT is known to handle specially.) Operations from
@racketmodname[racket/flonum] and @racketmodname[racket/unsafe/ops]
are always inlined, so @racketidfont{#%in} is not shown for them.}
@item{Function arguments and local bindings that are known to have a
particular type have names that embed the known type. For example, an
argument might have a name that starts @racketidfont{argflonum} or a
@ -123,14 +124,6 @@ Many forms in the decompiled code, such as @racket[module],
]
Command-line flags:
@itemlist[
@item{@Flag{n} @nonterm{n} or @DFlag{columns} @nonterm{n} --- format output for a display with @nonterm{n} columns}
@item{@Flag{h} or @DFlag{help} --- show help information for this command}
@item{@DFlag{} --- do not treat remaining arguments as switches}
]
@; ------------------------------------------------------------
@section{API for Decompiling}