Compare commits

..

No commits in common. "doc-change" and "master" have entirely different histories.

10 changed files with 8 additions and 414 deletions

View File

@ -6,7 +6,8 @@ env:
global:
- RACKET_DIR=~/racket
matrix:
- RACKET_VERSION=6.7
- RACKET_VERSION=6.2
- RACKET_VERSION=6.2.1
- RACKET_VERSION=HEAD
matrix:
@ -26,6 +27,6 @@ before_script:
script:
- raco pkg install --deps search-auto --link debug
- raco test -p debug
- raco test -x -p debug
after_script:

View File

@ -1,11 +1,9 @@
debug [![Build Status](https://travis-ci.org/AlexKnauth/debug.png?branch=master)](https://travis-ci.org/AlexKnauth/debug)
==
A lang-extension for debugging, based on sugar/debug from [mbutterick/sugar](https://github.com/mbutterick/sugar)
A meta-language for debugging, based on sugar/debug from [mbutterick/sugar](https://github.com/mbutterick/sugar)
documentation: http://pkg-build.racket-lang.org/doc/debug/index.html
### `#lang debug`
To debug the value of an expression, simply put `debug` in front of the language at the top of
the file (for instance `#lang debug racket`), and put `#R`, `#RR` or `#RRR` in front of the
expression.
@ -33,33 +31,3 @@ Shows the output:
(* 3 4) = 12
15
```
### `debug-repl`
```racket
> (require debug/repl)
> (define (f x y)
(debug-repl))
> (f 1 2)
-> ; in the debug-repl now
x
1
-> y
2
-> (+ x y)
3
-> ; exit the debug-repl by pressing ctrl-D
> ; back in the normal repl
(f (λ (g a) (g a)) (list add1 4))
-> ; a new debug-repl
x
#<procedure>
-> y
(list #<procedure:add1> 4)
-> (x string->number "3")
3
-> (x (first y) (second y))
5
-> ; exit this debug-repl by pressing ctrl-D
```

View File

@ -2,6 +2,3 @@
(define scribblings '(["scribblings/debug.scrbl" ()]))
(define compile-omit-paths
'("test/debug-repl-macros.rkt"
))

View File

@ -1,13 +0,0 @@
#lang racket/base
(provide make-variable-like-transformer)
(define make-variable-like-transformer
(with-handlers
([exn:fail:filesystem:missing-module?
(λ (e)
(dynamic-require 'unstable/syntax
'make-variable-like-transformer))])
(dynamic-require 'syntax/transformer
'make-variable-like-transformer)))

View File

@ -1,103 +0,0 @@
#lang racket/base
(provide debug-repl resume)
(require "private/make-variable-like-transformer.rkt"
racket/list
racket/splicing
(for-syntax racket/base
racket/list
syntax/parse
))
(define debug-repl-prompt-tag (make-continuation-prompt-tag 'debug-repl))
(define debug-repl-abort-handler values)
;; ----------------------------------------------------------------------------
(begin-for-syntax
;; syntax-find-local-variables : Syntax -> (Listof Id)
(define (syntax-find-local-variables stx)
(define debug-info (syntax-debug-info stx (syntax-local-phase-level) #t))
(define context (hash-ref debug-info 'context))
(define bindings (hash-ref debug-info 'bindings))
(remove-duplicates
(for/list ([binding (in-list bindings)]
#:when (hash-has-key? binding 'local)
#:when (context-subset? (hash-ref binding 'context) context))
(datum->syntax stx (hash-ref binding 'name) stx))
bound-identifier=?))
;; context-subset? : Context Context -> Boolean
(define (context-subset? a b)
;; TODO: use an actual set-of-scopes subset function
(list-prefix? a b))
;; non-macro-id? : Id -> Boolean
(define NON-MACRO (gensym 'NON-MACRO))
(define (non-macro-id? id)
(eq? NON-MACRO (syntax-local-value id (λ () NON-MACRO))))
)
(define-syntax debug-repl
(lambda (stx)
(syntax-parse stx
[(debug-repl)
#:do [(define all-vars (syntax-find-local-variables stx))
(define-values [xs ms]
(partition non-macro-id? all-vars))]
#:with [x ...] xs
#:with [m ...] ms
#:with [mv ...] (map (λ (m)
(datum->syntax
stx
`(quote ,(syntax-local-value m))))
ms)
#:with varref (syntax-local-introduce #'(#%variable-reference))
#'(debug-repl/varref+hash
varref
(list (list (quote-syntax x) (λ () x)) ...)
(list (list (quote-syntax m) mv) ...))])))
;; debug-repl/varref+hash :
;; Variable-Ref
;; (Listof (List Id (-> Any)))
;; (Listof (List Id Any))
;; ->
;; Any
(define (debug-repl/varref+hash varref var-list macro-list)
(define ns (variable-reference->namespace varref))
(define intro (make-syntax-introducer #true))
(for ([pair (in-list var-list)])
(namespace-define-transformer-binding!
ns
(intro (first pair))
(make-variable-like-transformer #`(#,(second pair)))))
(for ([pair (in-list macro-list)])
(namespace-define-transformer-binding!
ns
(intro (first pair))
(second pair)))
(define old-prompt-read (current-prompt-read))
(define old-eval (current-eval))
(define (new-prompt-read)
(write-char #\-)
(old-prompt-read))
(define (new-eval stx)
(old-eval (intro stx)))
(parameterize ([current-namespace ns]
[current-prompt-read new-prompt-read]
[current-eval new-eval])
(call-with-continuation-prompt
read-eval-print-loop
debug-repl-prompt-tag
debug-repl-abort-handler)))
;; namespace-define-transformer-binding! : Namespace Symbol Any -> Void
(define (namespace-define-transformer-binding! ns sym val)
(eval #`(define-syntax #,(datum->syntax #f sym) #,val) ns))
;; resume : Any ... -> Nothing
(define (resume . vs)
(apply abort-current-continuation debug-repl-prompt-tag vs))

View File

@ -1,19 +1,15 @@
#lang scribble/manual
@(require (for-label racket/base
debug/repl
))
@title{debug}
source code: @url{https://github.com/AlexKnauth/debug}
A racket lang-extension for debugging, based on sugar/debug.
A racket meta-language for debugging, based on sugar/debug.
@section{#lang debug}
@defmodule[debug #:lang]{
A lang-extension (like @racketmodname[at-exp]) that allows for quick debugging
A meta-language (like @racketmodname[at-exp]) that allows for quick debugging
shorthands to a program written in any racket-based language that looks at the
readtable.
}
@ -43,42 +39,3 @@ Examples:
;(* 3 4) = 12
;15
}
@section{debug-repl}
@defmodule[debug/repl]
@defform[(debug-repl)]{
Creates a repl for debugging, which can access local variables in the context
where it is used.
For example a @racket[(debug-repl)] in a @racket[let] form
@codeblock[#:keep-lang-line? #f]{
#lang racket
(let ([x 1] [y 2])
(debug-repl))
}
Will be able to access the @racket[x] and @racket[y] local variables (if
debugging information is enabled in DrRacket's
@seclink["Language" #:doc '(lib "scribblings/drracket/drracket.scrbl")]{
@onscreen{Choose Language}} window, or if the program was executed using
@exec{racket -l errortrace -t myprogram.rkt}).
It becomes much more useful in a function definition:
@codeblock[#:keep-lang-line? #f]{
#lang racket
(define (f x y)
(debug-repl))
}
Then if you call @racket[(f 1 2)], it will create a repl where @racket[x] is
@racket[1] and @racket[y] is @racket[2].
In one of these repls, you can try evaluating different expressions. If you're
debugging a higher-order function for example, you can try out the functions
it accepts or creates with multiple sets of arguments to see how they react.
@defproc[(resume [v any/c] ...) any]{
When called inside of a @racket[debug-repl], exits the repl. The call to
@racket[debug-repl] returns the arguments to @racket[resume].
}
}

View File

@ -1,92 +0,0 @@
#lang racket/base
(require "../repl.rkt"
"test-util.rkt"
rackunit
(for-syntax racket/base syntax/parse))
(define a 3)
(define b 4)
(test-case "local macros that don't refer to other macros"
(define (f tmp)
(define-syntax ?list
(syntax-parser
[(?list x:expr ...)
(define (?list-helper acc xs)
(syntax-parse (list acc xs)
[([acc:id ...] []) #'(list acc ...)]
[([acc:id ...] [x:expr y:expr ...])
#:with [tmp] (generate-temporaries #'[x])
#`(let ([tmp x])
(if tmp
#,(?list-helper #'[acc ... tmp] #'[y ...])
#false))]))
(?list-helper #'[] #'[x ...])]
[stx
;; TODO: figure out how to make syntax-parse's own errors
;; not cause infinite loops
(raise-syntax-error #f "bad syntax" #'stx)]))
(debug-repl)
tmp)
(test-with-io
#:i [i (open-input-string "a b tmp (?list a b tmp)")]
#:o [o (open-output-string)]
(check-equal? (f 1) 1)
(check-equal? (get-output-string o)
(string-append
"-> " #;a "3\n"
"-> " #;b "4\n"
"-> " #;tmp "1\n"
"-> " #;(?list a b tmp) "'(3 4 1)\n"
"-> ")))
(test-with-io
#:i [i (open-input-string "(?list . bluh)")]
#:o [o (open-output-string)]
(check-exn #rx"\\?list: bad syntax"
(λ () (f 1)))
(check-equal? (get-output-string o)
(string-append
"-> " #;(?list . bluh)))))
;; TODO: !!! identifier used out of context !!!
#;
(test-case "local macros that refer to other macros"
(define (f tmp)
(define-syntax ?list-helper
(syntax-parser
[(?list-helper [acc:id ...] []) #'(list acc ...)]
[(?list-helper [acc:id ...] [x:expr y:expr ...])
#'(let ([tmp x])
(if tmp
(?list-helper [acc ... tmp] [y ...])
#false))]))
(define-syntax-rule (?list x ...)
(?list-helper [] [x ...]))
(debug-repl)
tmp)
(test-with-io
#:i [i (open-input-string "a b tmp (?list a b tmp)")]
#:o [o (open-output-string)]
(check-equal? (f 1) 1)
(check-equal? (get-output-string o)
(string-append
"-> " #;a "3\n"
"-> " #;b "4\n"
"-> " #;tmp "1\n"
"-> " #;(?list a b tmp) "'(3 4 1)\n"
"-> ")))
(test-with-io
#:i [i (open-input-string "a b tmp (+ a b tmp)")]
#:o [o (open-output-string)]
(check-exn #rx"a: undefined;\n cannot use before initialization"
(λ () (f 1)))
(check-equal? (get-output-string o)
(string-append
"-> " #;b "4\n"
"-> " #;(+ b 13) "17\n"
"-> " #;(+ a b 13)))))

View File

@ -1,103 +0,0 @@
#lang racket/base
(require "../repl.rkt"
"test-util.rkt"
rackunit)
(define a 3)
(define b 4)
(define-syntax-rule (with-other-vars body)
(let ([x 5] [z 6])
;; x and z are not available outside this scope
body))
(define (f x y)
;; x and y are local variables
(with-other-vars
(let ([y 7] [b 8] [c 9])
;; y, b, and c are local variables
(debug-repl)
x)))
(test-with-io
#:i [i (open-input-string "x y a b c (+ x y a b c) (with-other-vars x)")]
#:o [o (open-output-string)]
(check-equal? (f 1 2) 1)
(check-equal? (get-output-string o)
(string-append
"-> " #;x "1\n"
"-> " #;y "7\n"
"-> " #;a "3\n"
"-> " #;b "8\n"
"-> " #;c "9\n"
"-> " #;(+ x y a b c) "28\n"
"-> " #;(with-other-vars x) "1\n"
"-> "))
)
;; test for issue #9
(test-case "issue #9"
(define (f)
(when #true
(debug-repl))
(define a 1)
a)
(test-with-io
#:i [i (open-input-string "b (+ b 13)")]
#:o [o (open-output-string)]
(check-equal? (f) 1)
(check-equal? (get-output-string o)
(string-append
"-> " #;b "4\n"
"-> " #;(+ b 13) "17\n"
"-> ")))
(test-with-io
#:i [i (open-input-string "b (+ b 13) (+ a b 13)")]
#:o [o (open-output-string)]
(check-exn #rx"a: undefined;\n cannot use before initialization"
(λ () (f)))
(check-equal? (get-output-string o)
(string-append
"-> " #;b "4\n"
"-> " #;(+ b 13) "17\n"
"-> " #;(+ a b 13)))))
;; test for mutation
(define x-for-mutation 1)
(test-case "test for mutation"
(define (f1 x-for-mutation)
(debug-repl)
x-for-mutation)
(define (f2)
(debug-repl)
x-for-mutation)
(test-with-io
#:i [i (open-input-string "x-for-mutation")]
#:o [o (open-output-string)]
(check-equal? x-for-mutation 1)
(check-equal? (f1 2) 2)
(check-equal? (get-output-string o)
(string-append
"-> " #;x-for-mutation "2\n"
"-> "))
(check-equal? x-for-mutation 1))
(test-with-io
#:i [i (open-input-string "x-for-mutation")]
#:o [o (open-output-string)]
(check-equal? x-for-mutation 1)
(check-equal? (f2) 1)
(check-equal? (get-output-string o)
(string-append
"-> " #;x-for-mutation "1\n"
"-> "))
(check-equal? x-for-mutation 1)))

View File

@ -1,14 +0,0 @@
#lang racket/base
(provide test-with-io)
(define-syntax-rule (test-with-io
#:i [i input-port]
#:o [o output-port]
body ...)
(let ([i input-port]
[o output-port])
(parameterize ([current-input-port i]
[current-output-port o])
body ...)))

View File

@ -2,13 +2,9 @@
(define collection 'multi)
;; Require a version of racket after this commit:
;; make `variable-reference->namespace` enable top-level mode
;; d1c2daf15b8be048b5cea63d5a1d7206bfc8d43f
(define deps
'(["base" #:version "6.6.0.3"]
"rackunit-lib"
'("rackunit-lib"
"base"
))
(define build-deps