factor/extra/tools/walker/walker.factor

233 lines
6.1 KiB
Factor
Raw Normal View History

2008-02-21 00:13:22 -05:00
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: threads kernel namespaces continuations combinators
sequences math namespaces.private continuations.private
concurrency.messaging quotations kernel.private words
sequences.private assocs models ;
IN: tools.walker
2007-12-31 22:16:21 -05:00
2008-02-20 00:26:07 -05:00
SYMBOL: walker-hook
! Thread local
2008-02-21 00:13:22 -05:00
SYMBOL: walker-thread
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: get-walker-thread ( -- thread )
walker-thread tget [
walker-hook get [ "No walker hook" throw ] or call
walker-thread tget
2008-02-20 00:26:07 -05:00
] unless* ;
2007-10-04 18:45:19 -04:00
2008-02-20 00:26:07 -05:00
: break ( -- )
callstack [
2008-02-21 00:13:22 -05:00
over set-continuation-call
2007-09-20 18:09:08 -04:00
2008-02-21 00:13:22 -05:00
get-walker-thread send-synchronous {
2008-02-20 00:26:07 -05:00
{ [ dup continuation? ] [ (continue) ] }
{ [ dup quotation? ] [ call ] }
{ [ dup not ] [ "Single stepping abandoned" throw ] }
} cond
] curry callcc0 ;
2007-09-20 18:09:08 -04:00
2008-02-21 00:13:22 -05:00
: walk ( quot -- ) \ break add* call ;
2007-10-04 18:45:19 -04:00
2008-02-21 00:13:22 -05:00
! Messages sent to walker thread
2008-02-20 00:26:07 -05:00
SYMBOL: step
SYMBOL: step-out
SYMBOL: step-into
SYMBOL: step-all
2008-02-21 00:13:22 -05:00
SYMBOL: step-into-all
2008-02-20 00:26:07 -05:00
SYMBOL: step-back
SYMBOL: detach
SYMBOL: abandon
SYMBOL: call-in
2007-09-20 18:09:08 -04:00
2008-02-20 00:26:07 -05:00
! Thread locals
2008-02-21 00:13:22 -05:00
SYMBOL: walker-status
SYMBOL: walker-continuation
SYMBOL: walker-history
SYMBOL: +running+
SYMBOL: +suspended+
SYMBOL: +stopped+
2008-02-20 00:26:07 -05:00
: change-frame ( continuation quot -- continuation' )
#! Applies quot to innermost call frame of the
#! continuation.
over continuation-call clone
[
dup innermost-frame-scan 1+
swap innermost-frame-quot
rot call
] keep
[ set-innermost-frame-quot ] keep
over set-continuation-call ; inline
: step-msg ( continuation -- continuation' )
[
2dup nth \ break = [
nip
] [
swap 1+ cut [ break ] swap 3append
] if
] change-frame ;
: step-out-msg ( continuation -- continuation' )
[ nip \ break add ] change-frame ;
GENERIC: (step-into) ( obj -- )
M: wrapper (step-into) wrapped break ;
M: object (step-into) break ;
M: callable (step-into) \ break add* break ;
2007-12-31 22:16:21 -05:00
: (step-into-if) ? walk ;
2007-09-20 18:09:08 -04:00
2008-02-20 00:26:07 -05:00
: (step-into-dispatch) nth walk ;
2007-09-20 18:09:08 -04:00
: (step-into-execute) ( word -- )
dup "step-into" word-prop [
call
] [
2008-01-02 19:36:36 -05:00
dup primitive? [
execute break
2008-01-02 19:36:36 -05:00
] [
word-def walk
] if
] ?if ;
2007-09-20 18:09:08 -04:00
2007-10-03 20:49:17 -04:00
: (step-into-continuation)
continuation callstack over set-continuation-call break ;
M: word (step-into) (step-into-execute) ;
{
2007-12-31 22:16:21 -05:00
{ call [ walk ] }
{ (throw) [ drop walk ] }
{ execute [ (step-into-execute) ] }
{ if [ (step-into-if) ] }
{ dispatch [ (step-into-dispatch) ] }
2007-10-03 20:49:17 -04:00
{ continuation [ (step-into-continuation) ] }
} [ "step-into" set-word-prop ] assoc-each
{
>n ndrop >c c>
2007-10-03 20:49:17 -04:00
continue continue-with
2008-02-21 00:13:22 -05:00
stop yield suspend sleep (spawn)
2008-02-20 00:26:07 -05:00
suspend
} [
dup [ execute break ] curry
"step-into" set-word-prop
] each
2007-09-20 18:09:08 -04:00
2007-10-09 01:30:28 -04:00
\ break [ break ] "step-into" set-word-prop
2008-02-20 00:26:07 -05:00
: step-into-msg ( continuation -- continuation' )
[
2007-10-12 16:30:36 -04:00
swap cut [
swap % unclip literalize , \ (step-into) , %
] [ ] make
2008-02-21 00:13:22 -05:00
] change-frame ;
2007-10-04 18:45:19 -04:00
2008-02-21 00:13:22 -05:00
: status ( -- symbol )
walker-status tget model-value ;
: set-status ( symbol -- )
walker-status tget set-model ;
2008-02-20 00:26:07 -05:00
: detach-msg ( -- f )
2008-02-21 00:13:22 -05:00
+stopped+ set-status ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: keep-running ( continuation -- continuation )
+running+ set-status
dup continuation? [ dup walker-history tget push ] when ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: walker-stopped ( -- )
+stopped+ set-status
[
{
{ detach [ detach-msg ] }
[ drop f ]
} case
] handle-synchronous
walker-stopped ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: step-into-all-loop ( -- )
+running+ set-status
[ status +stopped+ eq? not ] [
[
{
{ detach [ detach-msg ] }
{ step [ f ] }
{ step-out [ f ] }
{ step-into [ f ] }
{ step-all [ f ] }
{ step-into-all [ f ] }
{ step-back [ f ] }
{ f [ walker-stopped ] }
[ step-into-msg ]
} case
] handle-synchronous
] [ ] while ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: walker-suspended ( continuation -- continuation' )
+suspended+ set-status
[ status +suspended+ eq? ] [
2008-02-20 00:26:07 -05:00
[
{
2008-02-21 00:13:22 -05:00
! These are sent by the walker tool. We reply
! and keep cycling.
2008-02-20 00:26:07 -05:00
{ detach [ detach-msg ] }
! These change the state of the thread being
! interpreted, so we modify the continuation and
! output f.
2008-02-21 00:13:22 -05:00
{ step [ step-msg keep-running ] }
{ step-out [ step-out-msg keep-running ] }
{ step-into [ step-into-msg keep-running ] }
2008-02-20 00:26:07 -05:00
{ step-all [ keep-running ] }
2008-02-21 00:13:22 -05:00
{ step-into-all [ step-into-all-loop ] }
2008-02-20 00:26:07 -05:00
{ abandon [ drop f keep-running ] }
! Pass quotation to debugged thread
{ call-in [ nip keep-running ] }
! Pass previous continuation to debugged thread
2008-02-21 00:13:22 -05:00
{ step-back [ drop walker-history tget pop f ] }
2008-02-20 00:26:07 -05:00
} case
] handle-synchronous
2008-02-21 00:13:22 -05:00
] [ ] while ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: walker-loop ( -- )
+running+ set-status
[ status +stopped+ eq? not ] [
2008-02-20 00:26:07 -05:00
[
{
{ detach [ detach-msg ] }
! ignore these commands while the thread is
! running
{ step [ f ] }
{ step-out [ f ] }
{ step-into [ f ] }
{ step-all [ f ] }
2008-02-21 00:13:22 -05:00
{ step-into-all [ step-into-all-loop ] }
2008-02-20 00:26:07 -05:00
{ step-back [ f ] }
2008-02-21 00:13:22 -05:00
{ f [ walker-stopped f ] }
2008-02-20 00:26:07 -05:00
! thread hit a breakpoint and sent us the
2008-02-21 00:13:22 -05:00
! continuation, so we modify it and send it
! back.
[ walker-suspended ]
2008-02-20 00:26:07 -05:00
} case
] handle-synchronous
2008-02-21 00:13:22 -05:00
] [ ] while ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: associate-thread ( walker -- )
dup walker-thread tset
[ f swap send ] curry self set-thread-exit-handler ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: start-walker-thread ( status continuation -- thread' )
2008-02-20 00:26:07 -05:00
[
2008-02-21 00:13:22 -05:00
walker-continuation tset
walker-status tset
V{ } clone walker-history tset
walker-loop
] 2curry
"Walker on " self thread-name append spawn
[ associate-thread ] keep ;