271 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			271 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Factor
		
	
	
| ! Copyright (C) 2007, 2010 Daniel Ehrenberg, Bruno Deferrari,
 | |
| ! Slava Pestov.
 | |
| ! See http://factorcode.org/license.txt for BSD license.
 | |
| USING: accessors arrays assocs combinators compiler.units
 | |
| continuations hash-sets hashtables kernel math namespaces
 | |
| parser.notes sequences sets sorting splitting vectors vocabs
 | |
| words ;
 | |
| IN: vocabs.parser
 | |
| 
 | |
| ERROR: no-word-error name ;
 | |
| 
 | |
| : word-restarts ( possibilities -- restarts )
 | |
|     natural-sort [
 | |
|         [ vocabulary>> "Use the " " vocabulary" surround ] keep
 | |
|     ] { } map>assoc ;
 | |
| 
 | |
| : word-restarts-with-defer ( name possibilities -- restarts )
 | |
|     word-restarts
 | |
|     "Defer word in current vocabulary" rot 2array
 | |
|     suffix ;
 | |
| 
 | |
| : <no-word-error> ( name possibilities -- error restarts )
 | |
|     [ drop \ no-word-error boa ] [ word-restarts-with-defer ] 2bi ;
 | |
| 
 | |
| TUPLE: manifest
 | |
| current-vocab
 | |
| { search-vocab-names hash-set }
 | |
| { search-vocabs vector }
 | |
| { qualified-vocabs vector }
 | |
| { auto-used vector } ;
 | |
| 
 | |
| : <manifest> ( -- manifest )
 | |
|     manifest new
 | |
|         HS{ } clone >>search-vocab-names
 | |
|         V{ } clone >>search-vocabs
 | |
|         V{ } clone >>qualified-vocabs
 | |
|         V{ } clone >>auto-used ;
 | |
| 
 | |
| M: manifest clone
 | |
|     call-next-method
 | |
|         [ clone ] change-search-vocab-names
 | |
|         [ clone ] change-search-vocabs
 | |
|         [ clone ] change-qualified-vocabs
 | |
|         [ clone ] change-auto-used ;
 | |
| 
 | |
| TUPLE: extra-words words ;
 | |
| 
 | |
| M: extra-words equal?
 | |
|     over extra-words? [ [ words>> ] bi@ eq? ] [ 2drop f ] if ;
 | |
| 
 | |
| C: <extra-words> extra-words
 | |
| 
 | |
| ERROR: no-word-in-vocab word vocab ;
 | |
| 
 | |
| <PRIVATE
 | |
| 
 | |
| : (from) ( vocab words -- vocab words words' vocab )
 | |
|     2dup swap load-vocab ;
 | |
| 
 | |
| : extract-words ( seq vocab -- assoc )
 | |
|     [ words>> extract-keys dup ] [ name>> ] bi
 | |
|     [ swap [ 2drop ] [ no-word-in-vocab ] if ] curry assoc-each ;
 | |
| 
 | |
| : excluding-words ( seq vocab -- assoc )
 | |
|     [ nip words>> ] [ extract-words ] 2bi assoc-diff ;
 | |
| 
 | |
| : qualified-words ( prefix vocab -- assoc )
 | |
|     words>> swap [ swap [ swap ":" glue ] dip ] curry assoc-map ;
 | |
| 
 | |
| : (lookup) ( name assoc -- word/f )
 | |
|     at* [ dup forward-reference? [ drop f ] when ] when ;
 | |
| 
 | |
| PRIVATE>
 | |
| 
 | |
| : qualified-vocabs ( -- qualified-vocabs )
 | |
|     manifest get qualified-vocabs>> ;
 | |
| 
 | |
| : set-current-vocab ( name -- )
 | |
|     create-vocab
 | |
|     [ manifest get current-vocab<< ]
 | |
|     [ qualified-vocabs push ] bi ;
 | |
| 
 | |
| : with-current-vocab ( name quot -- )
 | |
|     manifest get clone manifest [
 | |
|         [ set-current-vocab ] dip call
 | |
|     ] with-variable ; inline
 | |
| 
 | |
| TUPLE: no-current-vocab-error ;
 | |
| 
 | |
| : no-current-vocab ( -- vocab )
 | |
|     no-current-vocab-error boa
 | |
|     { { "Define words in scratchpad vocabulary" "scratchpad" } }
 | |
|     throw-restarts dup set-current-vocab ;
 | |
| 
 | |
| : current-vocab ( -- vocab )
 | |
|     manifest get current-vocab>> [ no-current-vocab ] unless* ;
 | |
| 
 | |
| ERROR: unbalanced-private-declaration vocab ;
 | |
| 
 | |
| : begin-private ( -- )
 | |
|     current-vocab name>> ".private" ?tail
 | |
|     [ unbalanced-private-declaration ]
 | |
|     [ ".private" append set-current-vocab ] if ;
 | |
| 
 | |
| : end-private ( -- )
 | |
|     current-vocab name>> ".private" ?tail
 | |
|     [ set-current-vocab ]
 | |
|     [ unbalanced-private-declaration ] if ;
 | |
| 
 | |
| : using-vocab? ( vocab -- ? )
 | |
|     vocab-name manifest get search-vocab-names>> in? ;
 | |
| 
 | |
| : use-vocab ( vocab -- )
 | |
|     dup using-vocab? [
 | |
|         vocab-name "Already using ``" "'' vocabulary" surround note.
 | |
|     ] [
 | |
|         manifest get
 | |
|         [ [ load-vocab ] dip search-vocabs>> push ]
 | |
|         [ [ vocab-name ] dip search-vocab-names>> adjoin ]
 | |
|         2bi
 | |
|     ] if ;
 | |
| 
 | |
| : auto-use-vocab ( vocab -- )
 | |
|     [ use-vocab ] [ manifest get auto-used>> push ] bi ;
 | |
| 
 | |
| : auto-used? ( -- ? )
 | |
|     manifest get auto-used>> length 0 > ;
 | |
| 
 | |
| : unuse-vocab ( vocab -- )
 | |
|     dup using-vocab? [
 | |
|         manifest get
 | |
|         [ [ load-vocab ] dip search-vocabs>> remove-eq! drop ]
 | |
|         [ [ vocab-name ] dip search-vocab-names>> delete ]
 | |
|         2bi
 | |
|     ] [ drop ] if ;
 | |
| 
 | |
| TUPLE: qualified vocab prefix words ;
 | |
| 
 | |
| : <qualified> ( vocab prefix -- qualified )
 | |
|     (from) qualified-words qualified boa ;
 | |
| 
 | |
| : add-qualified ( vocab prefix -- )
 | |
|     <qualified> qualified-vocabs push ;
 | |
| 
 | |
| TUPLE: from vocab names words ;
 | |
| 
 | |
| : <from> ( vocab words -- from )
 | |
|     (from) extract-words from boa ;
 | |
| 
 | |
| : add-words-from ( vocab words -- )
 | |
|     <from> qualified-vocabs push ;
 | |
| 
 | |
| TUPLE: exclude vocab names words ;
 | |
| 
 | |
| : <exclude> ( vocab words -- from )
 | |
|     (from) excluding-words exclude boa ;
 | |
| 
 | |
| : add-words-excluding ( vocab words -- )
 | |
|     <exclude> qualified-vocabs push ;
 | |
| 
 | |
| TUPLE: rename word vocab words ;
 | |
| 
 | |
| : <rename> ( word vocab new-name -- rename )
 | |
|     [
 | |
|         2dup load-vocab words>> dupd at
 | |
|         [ ] [ swap no-word-in-vocab ] ?if
 | |
|     ] dip associate rename boa ;
 | |
| 
 | |
| : add-renamed-word ( word vocab new-name -- )
 | |
|     <rename> qualified-vocabs push ;
 | |
| 
 | |
| : use-words ( assoc -- )
 | |
|     <extra-words> qualified-vocabs push ;
 | |
| 
 | |
| : unuse-words ( assoc -- )
 | |
|     <extra-words> qualified-vocabs remove! drop ;
 | |
| 
 | |
| TUPLE: ambiguous-use-error name words ;
 | |
| 
 | |
| : <ambiguous-use-error> ( name words -- error restarts )
 | |
|     [ ambiguous-use-error boa ] [ word-restarts ] bi ;
 | |
| 
 | |
| <PRIVATE
 | |
| 
 | |
| : (vocab-search) ( name assocs -- words )
 | |
|     [ words>> (lookup) ] with map sift ;
 | |
| 
 | |
| : (vocab-search-qualified) ( name assocs -- words )
 | |
|     [ ":" split1 swap ] dip [ name>> = ] with filter (vocab-search) ;
 | |
| 
 | |
| : (vocab-search-full) ( name assocs -- words )
 | |
|     [ (vocab-search-qualified) ] [ (vocab-search) ] 2bi append ;
 | |
| 
 | |
| : vocab-search ( name manifest -- word/f )
 | |
|     dupd search-vocabs>> (vocab-search-full) dup length {
 | |
|         { 0 [ 2drop f ] }
 | |
|         { 1 [ first nip ] }
 | |
|         [
 | |
|             drop <ambiguous-use-error> throw-restarts
 | |
|             dup [ vocabulary>> ] [ name>> 1array ] bi add-words-from
 | |
|         ]
 | |
|     } case ;
 | |
| 
 | |
| : qualified-search ( name manifest -- word/f )
 | |
|     qualified-vocabs>> (vocab-search) ?last ;
 | |
| 
 | |
| PRIVATE>
 | |
| 
 | |
| : search-manifest ( name manifest -- word/f )
 | |
|     2dup qualified-search [ 2nip ] [ vocab-search ] if* ;
 | |
| 
 | |
| : search ( name -- word/f )
 | |
|     manifest get search-manifest ;
 | |
| 
 | |
| <PRIVATE
 | |
| 
 | |
| GENERIC: update ( search-path-elt -- valid? )
 | |
| 
 | |
| : trim-forgotten ( qualified-vocab -- valid? )
 | |
|     [ [ nip "forgotten" word-prop ] assoc-reject ] change-words
 | |
|     words>> assoc-empty? not ;
 | |
| 
 | |
| M: from update trim-forgotten ;
 | |
| M: rename update trim-forgotten ;
 | |
| M: extra-words update trim-forgotten ;
 | |
| M: exclude update trim-forgotten ;
 | |
| 
 | |
| M: qualified update
 | |
|     dup vocab>> lookup-vocab [
 | |
|         dup [ prefix>> ] [ vocab>> load-vocab ] bi qualified-words
 | |
|         >>words
 | |
|     ] [ drop f ] if ;
 | |
| 
 | |
| M: vocab update dup name>> lookup-vocab eq? ;
 | |
| 
 | |
| : update-current-vocab ( manifest -- manifest )
 | |
|     [ dup [ name>> lookup-vocab ] when ] change-current-vocab ; inline
 | |
| 
 | |
| : compute-search-vocabs ( manifest -- search-vocab-names search-vocabs )
 | |
|     search-vocab-names>> members dup length <vector> [
 | |
|         [ push ] curry [ when* ] curry
 | |
|         [ lookup-vocab dup ] prepose filter fast-set
 | |
|     ] keep ; inline
 | |
| 
 | |
| : update-search-vocabs ( manifest -- manifest )
 | |
|     dup compute-search-vocabs
 | |
|     [ >>search-vocab-names ] [ >>search-vocabs ] bi* ; inline
 | |
| 
 | |
| : update-qualified-vocabs ( manifest -- manifest )
 | |
|     dup qualified-vocabs>> [ update ] filter! drop ; inline
 | |
| 
 | |
| : update-manifest ( manifest -- manifest )
 | |
|     update-current-vocab
 | |
|     update-search-vocabs
 | |
|     update-qualified-vocabs ; inline
 | |
| 
 | |
| M: manifest definitions-changed
 | |
|     nip update-manifest drop ;
 | |
| 
 | |
| PRIVATE>
 | |
| 
 | |
| : with-manifest ( quot -- )
 | |
|     <manifest> manifest [
 | |
|         [ call ] [
 | |
|             [ manifest get add-definition-observer call ]
 | |
|             [ manifest get remove-definition-observer ]
 | |
|             [ ]
 | |
|             cleanup
 | |
|         ] if-bootstrapping
 | |
|     ] with-variable ; inline
 |