factor/extra/gml/runtime/runtime.factor

210 lines
5.4 KiB
Factor

! Copyright (C) 2010 Slava Pestov.
USING: accessors arrays assocs fry generic.parser kernel locals
locals.parser macros math math.ranges memoize parser sequences
sequences.private strings strings.parser lexer namespaces
vectors words generalizations sequences.generalizations
effects.parser gml.types ;
IN: gml.runtime
TUPLE: name < identity-tuple { string read-only } ;
SYMBOL: names
names [ H{ } clone ] initialize
: name ( string -- name ) names get-global [ \ name boa ] cache ;
TUPLE: gml { operand-stack vector } { dictionary-stack vector } ;
: push-operand ( value gml -- ) operand-stack>> push ; inline
: peek-operand ( gml -- value ? )
operand-stack>> [ f f ] [ last t ] if-empty ; inline
: pop-operand ( gml -- value ) operand-stack>> pop ; inline
GENERIC: (exec) ( registers gml obj -- registers gml )
! A bit of efficiency
FROM: kernel.private => declare ;
: is-gml ( registers gml obj -- registers gml obj )
{ array gml object } declare ; inline
<<
: (EXEC:) ( quot -- method def )
scan-word \ (exec) create-method-in
swap call( -- quot ) [ is-gml ] prepend ;
SYNTAX: EXEC: [ parse-definition ] (EXEC:) define ;
SYNTAX: EXEC:: [ [ parse-definition ] parse-locals-definition drop ] (EXEC:) define ;
>>
! Literals
EXEC: object over push-operand ;
EXEC: proc array>> pick <proc> over push-operand ;
! Executable names
TUPLE: exec-name < identity-tuple name ;
MEMO: exec-name ( string -- name ) name \ exec-name boa ;
SYNTAX: exec" lexer get skip-blank parse-string exec-name suffix! ;
ERROR: unbound-name { name name } ;
: lookup-name ( name gml -- value )
dupd dictionary-stack>> assoc-stack
[ ] [ unbound-name ] ?if ; inline
GENERIC: exec-proc ( registers gml proc -- registers gml )
M:: proc exec-proc ( registers gml proc -- registers gml )
proc registers>>
gml
proc array>> [ (exec) ] each 2drop
registers gml ;
FROM: combinators.private => execute-effect-unsafe ;
CONSTANT: primitive-effect ( registers gml -- registers gml )
M: word exec-proc primitive-effect execute-effect-unsafe ;
M: object exec-proc (exec) ;
EXEC: exec-name name>> over lookup-name exec-proc ;
! Registers
ERROR: unbound-register name ;
:: lookup-register ( registers gml obj -- value )
obj n>> registers nth [
obj name>> unbound-register
] unless* ;
TUPLE: read-register { name string } { n fixnum } ;
: <read-register> ( name -- read-register ) 0 read-register boa ;
EXEC: read-register
[ 2dup ] dip lookup-register over push-operand ;
TUPLE: exec-register { name string } { n fixnum } ;
: <exec-register> ( name -- exec-register ) 0 exec-register boa ;
EXEC: exec-register
[ 2dup ] dip lookup-register exec-proc ;
TUPLE: write-register { name string } { n fixnum } ;
: <write-register> ( name -- write-register ) 0 write-register boa ;
EXEC:: write-register ( registers gml obj -- registers gml )
gml pop-operand obj n>> registers set-nth
registers gml ;
TUPLE: use-registers { n fixnum } ;
: <use-registers> ( -- use-registers ) use-registers new ;
EXEC: use-registers
n>> f <array> '[ drop _ ] dip ;
! Pathnames
TUPLE: pathname names ;
C: <pathname> pathname
: at-pathname ( pathname assoc -- value )
swap names>> [ swap ?at [ unbound-name ] unless ] each ;
EXEC:: pathname ( registers gml obj -- registers gml )
obj gml pop-operand at-pathname gml push-operand
registers gml ;
! List building and stuff
TUPLE: marker < identity-tuple ;
CONSTANT: marker T{ marker }
ERROR: no-marker-found ;
ERROR: gml-stack-underflow ;
: find-marker ( gml -- n )
operand-stack>> [ marker eq? ] find-last
[ 1 + ] [ no-marker-found ] if ; inline
! Primitives
: check-stack ( seq n -- seq n )
2dup swap length > [ gml-stack-underflow ] when ; inline
: lastn ( seq n -- elts... )
check-stack
[ tail-slice* ] keep firstn-unsafe ; inline
: popn ( seq n -- elts... )
check-stack
[ lastn ] [ over length swap - swap shorten ] 2bi ; inline
: set-lastn ( elts... seq n -- )
[ tail-slice* ] keep set-firstn-unsafe ; inline
: pushn ( elts... seq n -- )
[ over length + swap lengthen ] 2keep set-lastn ; inline
MACRO: inputs ( inputs# -- quot: ( gml -- gml inputs... ) )
'[ dup operand-stack>> _ popn ] ;
MACRO: outputs ( outputs# -- quot: ( gml outputs... -- gml ) )
[ 1 + ] keep '[ _ npick operand-stack>> _ pushn ] ;
MACRO: gml-primitive (
inputs#
outputs#
quot: ( registers gml inputs... -- outputs... )
--
quot: ( registers gml -- registers gml )
)
swap '[ _ inputs @ _ outputs ] ;
SYMBOL: global-dictionary
global-dictionary [ H{ } clone ] initialize
: add-primitive ( word name -- )
name global-dictionary get-global set-at ;
: define-gml-primitive ( word name effect def -- )
[ '[ _ add-primitive ] keep ]
[ [ in>> length ] [ out>> length ] bi ]
[ '[ { gml } declare _ _ _ gml-primitive ] ] tri*
primitive-effect define-declared ;
: scan-gml-name ( -- word name )
scan-token [ "gml-" prepend create-word-in ] keep ;
: (GML:) ( -- word name effect def )
scan-gml-name scan-effect parse-definition ;
SYNTAX: GML:
(GML:) define-gml-primitive ;
SYNTAX: GML::
[let
scan-gml-name :> ( word name )
word [ parse-definition ] parse-locals-definition :> ( word def effect )
word name effect def define-gml-primitive
] ;
: <gml> ( -- gml )
gml new
global-dictionary get clone 1vector >>dictionary-stack
V{ } clone >>operand-stack ;
: exec ( gml proc -- gml ) [ { } ] 2dip exec-proc nip ;