factor/library/tools/interpreter.factor

179 lines
4.3 KiB
Factor
Raw Normal View History

2006-05-15 01:49:07 -04:00
! Copyright (C) 2004, 2006 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: arrays errors generic io kernel kernel-internals math
2006-08-24 02:40:03 -04:00
namespaces prettyprint sequences strings threads vectors words
hashtables ;
2006-09-08 02:32:14 -04:00
IN: interpreter
2006-08-24 02:40:03 -04:00
! Metacircular interpreter for single-stepping
2006-08-24 02:09:54 -04:00
SYMBOL: meta-interp
2006-05-15 01:37:11 -04:00
! Meta-stacks;
2006-08-24 02:09:54 -04:00
: meta-d meta-interp get continuation-data ;
: push-d meta-d push ;
: pop-d meta-d pop ;
: peek-d meta-d peek ;
: meta-r meta-interp get continuation-retain ;
: push-r meta-r push ;
: pop-r meta-r pop ;
: peek-r meta-r peek ;
: meta-c meta-interp get continuation-call ;
: push-c meta-c push ;
: pop-c meta-c pop ;
: peek-c meta-c peek ;
! Call frame
SYMBOL: callframe
SYMBOL: callframe-scan
SYMBOL: callframe-end
2006-09-08 02:32:14 -04:00
! Hook
SYMBOL: break-hook
2006-07-10 00:51:22 -04:00
: meta-callframe ( -- seq )
{ callframe callframe-scan callframe-end } [ get ] map ;
2006-07-30 21:32:21 -04:00
: (meta-call) ( quot -- )
dup callframe set
length callframe-end set
0 callframe-scan set ;
! Callframe.
: up ( -- )
pop-c callframe-end set
pop-c callframe-scan set
pop-c callframe set ;
2006-07-30 21:32:21 -04:00
: done-cf? ( -- ? ) callframe-scan get callframe-end get >= ;
2006-08-24 02:09:54 -04:00
: done? ( -- ? ) done-cf? meta-c empty? and ;
2006-07-30 21:32:21 -04:00
: (next)
callframe-scan get callframe get nth callframe-scan inc ;
2006-07-31 21:00:07 -04:00
: next ( quot -- )
2006-07-30 21:32:21 -04:00
{
2006-07-30 22:05:44 -04:00
{ [ done? ] [ drop [ ] (meta-call) ] }
2006-07-30 21:32:21 -04:00
{ [ done-cf? ] [ drop up ] }
{ [ t ] [ >r (next) r> call ] }
} cond ; inline
2006-09-08 02:32:14 -04:00
: reset-interpreter ( -- )
meta-interp off f (meta-call) ;
: (save-callframe) ( -- )
callframe get push-c
callframe-scan get push-c
callframe-end get push-c ;
2005-06-15 23:27:28 -04:00
: save-callframe ( -- )
2006-09-08 02:32:14 -04:00
done-cf? [ (save-callframe) ] unless ;
: meta-call ( quot -- )
#! Note we do tail call optimization here.
2006-07-30 21:32:21 -04:00
save-callframe (meta-call) ;
2006-09-08 02:32:14 -04:00
: break ( -- )
continuation get-walker-hook
[ continue-with ] [ break-hook get call ] if* ;
: <callframe> ( quot -- seq )
2006-09-08 02:32:14 -04:00
\ break add >quotation 0 over length 3array >vector ;
: restore-normally meta-interp set ;
: restore-transfer
first meta-interp set f (meta-call) ;
: restore-transfer-with
first2 meta-interp set push-d
meta-d [ length 1- dup 1- ] keep exchange
[ ] (meta-call) ;
: restore-harness ( obj -- )
{
2006-09-08 02:32:14 -04:00
{ [ dup continuation? ] [ restore-normally ] }
{ [ dup length 0 = ] [ drop reset-interpreter ] }
{ [ dup length 1 = ] [ restore-transfer ] }
{ [ dup length 2 = ] [ restore-transfer-with ] }
} cond ;
: host-quot ( quot -- )
<callframe> meta-c swap nappend
2006-09-07 17:58:27 -04:00
[ set-walker-hook meta-interp get (continue) ] callcc1
restore-harness ;
2006-07-30 22:05:44 -04:00
: host-word ( word -- ) unit host-quot ;
2005-09-28 20:09:10 -04:00
GENERIC: do-1 ( object -- )
M: word do-1
2005-09-28 20:09:10 -04:00
dup "meta-word" word-prop [ call ] [ host-word ] ?if ;
M: wrapper do-1 wrapped push-d ;
2005-09-28 20:09:10 -04:00
M: object do-1 push-d ;
2005-09-28 20:09:10 -04:00
GENERIC: do ( obj -- )
M: word do
dup "meta-word" word-prop [
2005-01-02 23:57:54 -05:00
call
] [
dup compound? [ word-def meta-call ] [ host-word ] if
2005-09-24 15:21:17 -04:00
] ?if ;
M: object do do-1 ;
2005-03-10 17:57:22 -05:00
2005-12-03 17:34:59 -05:00
! The interpreter loses object identity of the name and catch
! stacks -- they are copied after each step -- so we execute
2006-06-04 16:20:40 -04:00
! these atomically and don't allow stepping into these words
2006-09-08 02:32:14 -04:00
{ >n n> >c c> rethrow continue continue-with continuation
(continue) (continue-with) }
[ dup [ host-word ] curry "meta-word" set-word-prop ] each
2005-12-03 17:34:59 -05:00
2005-09-28 20:09:10 -04:00
\ call [ pop-d meta-call ] "meta-word" set-word-prop
\ execute [ pop-d do ] "meta-word" set-word-prop
\ if [ pop-d pop-d pop-d [ nip ] [ drop ] if meta-call ] "meta-word" set-word-prop
\ dispatch [ pop-d pop-d swap nth meta-call ] "meta-word" set-word-prop
2006-07-30 21:32:21 -04:00
2006-08-24 02:40:03 -04:00
! Time travel
SYMBOL: meta-history
2006-07-30 21:32:21 -04:00
2006-08-24 02:40:03 -04:00
: save-interp ( -- )
meta-history get [
[
callframe [ ] change
callframe-scan [ ] change
callframe-end [ ] change
meta-interp [ clone ] change
] make-hash swap push
] when* ;
: restore-interp ( ns -- )
{ callframe callframe-scan callframe-end }
[ dup pick hash swap set ] each
meta-interp swap hash clone meta-interp set ;
: step ( -- ) save-interp [ do-1 ] next ;
: step-in ( -- ) save-interp [ do ] next ;
2006-07-30 22:20:52 -04:00
: step-out ( -- )
2006-08-24 02:40:03 -04:00
save-interp
callframe get callframe-scan get tail
host-quot [ ] (meta-call) ;
2006-07-30 22:20:52 -04:00
: step-all ( -- )
save-callframe meta-interp get schedule-thread ;
2006-08-24 02:40:03 -04:00
: step-back ( -- )
meta-history get dup empty? [
drop
] [
pop restore-interp
] if ;