]> gitweb.factorcode.org Git - factor.git/commitdiff
classes: add syntax for intersection{ and union{ anonymous classes. make classoid...
authorDoug Coleman <doug.coleman@gmail.com>
Wed, 23 Nov 2011 02:49:18 +0000 (18:49 -0800)
committerDoug Coleman <doug.coleman@gmail.com>
Wed, 23 Nov 2011 02:49:42 +0000 (18:49 -0800)
17 files changed:
basis/compiler/tree/propagation/simple/simple.factor
basis/prettyprint/backend/backend.factor
basis/prettyprint/prettyprint-tests.factor
basis/typed/typed-tests.factor
basis/typed/typed.factor
core/bootstrap/syntax.factor
core/classes/algebra/algebra.factor
core/classes/classes.factor
core/classes/intersection/intersection-tests.factor
core/classes/intersection/intersection.factor
core/classes/maybe/maybe.factor
core/classes/tuple/tuple-tests.factor
core/classes/union/union-tests.factor
core/effects/effects.factor
core/generic/generic.factor
core/slots/slots.factor
core/syntax/syntax.factor

index e1bcc07ef40e52dce3ad9efc5504a912ad203ea7..504b28b400326874e3d64f5f20b2dc42af32f7f9 100644 (file)
@@ -40,6 +40,12 @@ M: class depends-on-class
 M: maybe depends-on-class
     class>> depends-on-class ;
 
+M: anonymous-union depends-on-class
+    members>> [ depends-on-class ] each ;
+
+M: anonymous-intersection depends-on-class
+    participants>> [ depends-on-class ] each ;
+
 M: #declare propagate-before
     #! We need to force the caller word to recompile when the
     #! classes mentioned in the declaration are redefined, since
index 3e85f0acafcaeb464958ef470730832c075c9838..105750bbb39fb7f16b59b094826681337d088de7 100644 (file)
@@ -1,13 +1,13 @@
 ! Copyright (C) 2003, 2009 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors arrays assocs byte-arrays byte-vectors classes
-classes.tuple classes.tuple.private colors colors.constants
-combinators continuations effects generic hashtables io
-io.pathnames io.styles kernel make math math.order math.parser
-namespaces prettyprint.config prettyprint.custom
-prettyprint.sections prettyprint.stylesheet quotations sbufs
-sequences strings vectors words words.symbol hash-sets
-classes.maybe ;
+classes.algebra.private classes.intersection classes.maybe
+classes.tuple classes.tuple.private classes.union colors
+colors.constants combinators continuations effects generic
+hash-sets hashtables io io.pathnames io.styles kernel make math
+math.order math.parser namespaces prettyprint.config
+prettyprint.custom prettyprint.sections prettyprint.stylesheet
+quotations sbufs sequences strings vectors words words.symbol ;
 FROM: sets => members ;
 IN: prettyprint.backend
 
@@ -28,6 +28,12 @@ GENERIC: word-name* ( obj -- str )
 M: maybe word-name*
     class>> word-name* "maybe: " prepend ;
 
+M: anonymous-union word-name*
+    members>> [ word-name* ] map " " join "union{ " " }" surround ;
+
+M: anonymous-intersection word-name*
+    participants>> [ word-name* ] map " " join "intersection{ " " }" surround ;
+
 M: word word-name* ( word -- str )
     [ name>> "( no name )" or ] [ record-vocab ] bi ;
 
@@ -36,10 +42,12 @@ M: word word-name* ( word -- str )
 
 GENERIC: pprint-class ( obj -- )
 
-M: maybe pprint-class pprint* ;
+M: classoid pprint-class pprint* ;
 
 M: class pprint-class \ f or pprint-word ;
 
+M: word pprint-class pprint-word ;
+
 : pprint-prefix ( word quot -- )
     <block swap pprint-word call block> ; inline
 
@@ -255,3 +263,9 @@ M: wrapper pprint*
 
 M: maybe pprint*
     <block \ maybe: pprint-word class>> pprint-word block> ;
+
+M: anonymous-union pprint*
+    <block \ union{ pprint-word members>> [ pprint-word ] each \ } pprint-word block> ;
+
+M: anonymous-intersection pprint*
+    <block \ intersection{ pprint-word participants>> [ pprint-word ] each \ } pprint-word block> ;
index 2ce227674ec37bd3818595762be778b9da5320b3..49dcbab433cd0f374366d491cb8468ebc7d0912e 100644 (file)
@@ -1,10 +1,11 @@
-USING: arrays definitions io.streams.string io.streams.duplex
-kernel math namespaces parser prettyprint prettyprint.config
-prettyprint.sections sequences tools.test vectors words
-effects splitting generic.standard prettyprint.private
-continuations generic compiler.units tools.continuations
-tools.continuations.private eval accessors make vocabs.parser see
-listener classes.maybe ;
+USING: accessors arrays classes.intersection classes.maybe
+classes.union compiler.units continuations definitions effects
+eval generic generic.standard io io.streams.duplex
+io.streams.string kernel listener make math namespaces parser
+prettyprint prettyprint.config prettyprint.private
+prettyprint.sections see sequences splitting
+tools.continuations tools.continuations.private tools.test
+vectors vocabs.parser words ;
 IN: prettyprint.tests
 
 [ "4" ] [ 4 unparse ] unit-test
@@ -406,3 +407,25 @@ M: integer harhar M\\ integer harhar drop ;\n"""
 ] [
     [ \ harhar see-methods ] with-string-writer
 ] unit-test
+
+
+TUPLE: mo { a union{ float integer } } ;
+TUPLE: fo { a intersection{ fixnum integer } } ;
+
+[
+"""USING: classes.union math ;
+IN: prettyprint.tests
+TUPLE: mo { a union{ float integer } initial: 0 } ;
+"""
+] [
+    [ \ mo see ] with-string-writer
+] unit-test
+
+[
+"""USING: classes.intersection math ;
+IN: prettyprint.tests
+TUPLE: fo { a intersection{ fixnum integer } initial: 0 } ;
+"""
+] [
+    [ \ fo see ] with-string-writer
+] unit-test
index e1ee431c535d7496da2f90fcfd4f7542e1de2864..5209038473f4f81f928eb36f5eb0da2ea3e0688e 100644 (file)
@@ -1,6 +1,7 @@
 USING: accessors effects eval kernel layouts math namespaces
 quotations tools.test typed words words.symbol combinators.short-circuit
-compiler.tree.debugger prettyprint definitions compiler.units sequences ;
+compiler.tree.debugger prettyprint definitions compiler.units sequences
+classes.intersection strings classes.union ;
 IN: typed.tests
 
 TYPED: f+ ( a: float b: float -- c: float )
@@ -167,3 +168,14 @@ TYPED: typed-maybe ( x: maybe: integer -- ? ) >boolean ;
 [ f ] [ f typed-maybe ] unit-test
 [ t ] [ 30 typed-maybe ] unit-test
 [ 30.0 typed-maybe ] [ input-mismatch-error? ] must-fail-with
+
+TYPED: typed-union ( x: union{ integer string } -- ? ) >boolean ;
+
+[ t ] [ 3 typed-union ] unit-test
+[ t ] [ "asdf" typed-union ] unit-test
+[ 3.3 typed-union ] [ input-mismatch-error? ] must-fail-with
+
+TYPED: typed-intersection ( x: intersection{ integer bignum } -- ? ) >boolean ;
+
+[ t ] [ 5555555555555555555555555555555555555555555555555555 typed-intersection ] unit-test
+[ 0 typed-intersection ] [ input-mismatch-error? ] must-fail-with
index fc1eee608c88449cad176402d22f0a30437cea79..4bd692dbfe419cda9519548a8eb0b0f6d6e3f142 100644 (file)
@@ -4,7 +4,7 @@ combinators.short-circuit definitions effects fry hints
 math kernel kernel.private namespaces parser quotations
 sequences slots words locals effects.parser
 locals.parser macros stack-checker.dependencies
-classes.maybe ;
+classes.maybe classes.algebra ;
 FROM: classes.tuple.private => tuple-layout ;
 IN: typed
 
@@ -19,7 +19,7 @@ PREDICATE: typed-word < word "typed-word" word-prop >boolean ;
 
 : unboxable-tuple-class? ( type -- ? )
     {
-        [ maybe? not ]
+        [ only-classoid? not ]
         [ all-slots empty? not ]
         [ immutable-tuple-class? ]
         [ final-class? ]
index 8e9acd150742be7266b470154d3acaea3de84159..3a99923b9e7d5e8d3296ba3b9102d80d0b8bda3a 100644 (file)
@@ -86,6 +86,8 @@ IN: bootstrap.syntax
         ">>"
         "call-next-method"
         "maybe:"
+        "union{"
+        "intersection{"
         "initial:"
         "read-only"
         "call("
index 5380e28d981ad2aed92a454d9b7070a60a5fa934..fcdab0eac6b55ad00bfd303a36c0b3b05b761ab4 100644 (file)
@@ -11,6 +11,8 @@ IN: classes.algebra
 
 TUPLE: anonymous-union { members read-only } ;
 
+INSTANCE: anonymous-union classoid
+
 : <anonymous-union> ( members -- class )
     [ null eq? not ] filter set-members
     dup length 1 = [ first ] [ anonymous-union boa ] if ;
@@ -19,6 +21,8 @@ M: anonymous-union rank-class drop 6 ;
 
 TUPLE: anonymous-intersection { participants read-only } ;
 
+INSTANCE: anonymous-intersection classoid
+
 : <anonymous-intersection> ( participants -- class )
     set-members dup length 1 =
     [ first ] [ anonymous-intersection boa ] if ;
@@ -27,6 +31,8 @@ M: anonymous-intersection rank-class drop 4 ;
 
 TUPLE: anonymous-complement { class read-only } ;
 
+INSTANCE: anonymous-complement classoid
+
 C: <anonymous-complement> anonymous-complement
 
 M: anonymous-complement rank-class drop 3 ;
@@ -52,19 +58,16 @@ M: object normalize-class ;
 
 PRIVATE>
 
-GENERIC: classoid? ( obj -- ? )
-
-M: word classoid? class? ;
-M: anonymous-union classoid? drop t ;
-M: anonymous-intersection classoid? drop t ;
-M: anonymous-complement classoid? drop t ;
-
 GENERIC: valid-classoid? ( obj -- ? )
 
 M: word valid-classoid? class? ;
 M: anonymous-union valid-classoid? members>> [ valid-classoid? ] all? ;
 M: anonymous-intersection valid-classoid? participants>> [ valid-classoid? ] all? ;
 M: anonymous-complement valid-classoid? class>> valid-classoid? ;
+M: object valid-classoid? drop f ;
+
+: only-classoid? ( obj -- ? )
+    [ classoid? ] [ class? not ] bi and ;
 
 : class<= ( first second -- ? )
     class<=-cache get [ (class<=) ] 2cache ;
index 051fbb7203803fa557ccd6411c9e4e01a6e9034f..3256785ecb2a47cf96f1dc18896f3ef4dfaa4526 100644 (file)
@@ -1,9 +1,7 @@
 ! Copyright (C) 2004, 2010 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays definitions assocs kernel kernel.private
-slots.private namespaces make sequences strings words words.symbol
-vectors math quotations combinators sorting effects graphs
-vocabs sets ;
+USING: accessors assocs combinators definitions graphs kernel
+make namespaces quotations sequences sets words words.symbol ;
 FROM: namespaces => set ;
 IN: classes
 
@@ -11,6 +9,9 @@ ERROR: bad-inheritance class superclass ;
 
 PREDICATE: class < word "class" word-prop ;
 
+MIXIN: classoid
+INSTANCE: class classoid
+
 <PRIVATE
 
 SYMBOL: class<=-cache
index 57e716fe44edab20b04cd2087a0e22499e76ac95..b0435a211996f9c095297392d2cd0a3b087bd19e 100644 (file)
@@ -1,4 +1,5 @@
-USING: kernel tools.test generic generic.standard ;
+USING: kernel tools.test generic generic.standard classes math
+accessors classes.intersection slots math.order ;
 IN: classes.intersection.tests
 
 TUPLE: a ;
@@ -35,4 +36,24 @@ M: i g drop i ;
 M: t4 g drop t4 ;
 
 [ t4 ] [ T{ t4 } g ] unit-test
-[ i ] [ T{ t5 } g ] unit-test
\ No newline at end of file
+[ i ] [ T{ t5 } g ] unit-test
+
+PREDICATE: odd-integer < integer odd? ;
+
+! [ TUPLE: omg { a intersection{ fixnum odd-integer } initial: 2 } ;" eval( -- ) ]
+! [ bad-initial-value? ] must-fail-with
+
+TUPLE: omg { a intersection{ fixnum odd-integer } initial: 1 } ;
+
+[ 1 ] [ omg new a>> ] unit-test
+[ 3 ] [ omg new 3 >>a a>> ] unit-test
+[ omg new 1.2 >>a a>> ] [ bad-slot-value? ] must-fail-with
+
+PREDICATE: odd/float-between-10-20 < union{ odd-integer float }
+    10 20 between? ;
+
+[ t ] [ 17 odd/float-between-10-20? ] unit-test
+[ t ] [ 17.4 odd/float-between-10-20? ] unit-test
+[ f ] [ 18 odd/float-between-10-20? ] unit-test
+[ f ] [ 5 odd/float-between-10-20? ] unit-test
+[ f ] [ 5.75 odd/float-between-10-20? ] unit-test
index 0ed4f4b6369175b68f26a15fa107fb094108577e..20b456648f61d3fa4c6185762403df50b9c41cdd 100644 (file)
@@ -30,6 +30,9 @@ M: intersection-class rank-class drop 5 ;
 M: intersection-class instance?
     "participants" word-prop [ instance? ] with all? ;
 
+M: anonymous-intersection instance?
+    participants>> [ instance? ] with all? ;
+
 M: intersection-class normalize-class
     participants <anonymous-intersection> normalize-class ;
 
index 30da5a58697eb7ea318bb379b96db8fb5bf5945e..30c09e923701d5b6b9e2098e62435c73244cc64e 100644 (file)
@@ -9,6 +9,8 @@ TUPLE: maybe { class word initial: object read-only } ;
 
 C: <maybe> maybe
 
+INSTANCE: maybe classoid
+
 M: maybe instance?
     over [ class>> instance? ] [ 2drop t ] if ;
 
@@ -18,8 +20,6 @@ M: maybe instance?
 M: maybe normalize-class
     maybe-class-or ;
 
-M: maybe classoid? drop t ;
-
 M: maybe valid-classoid? class>> valid-classoid? ;
 
 M: maybe rank-class drop 6 ;
@@ -27,8 +27,6 @@ M: maybe rank-class drop 6 ;
 M: maybe (flatten-class)
     maybe-class-or (flatten-class) ;
 
-M: maybe effect>type ;
-
 M: maybe union-of-builtins?
     class>> union-of-builtins? ;
 
index 9ac04464c7c531e3ba1aa77bba2737672649ded8..3aa225b1f5e321d7e590d596ac225007b76b88b1 100644 (file)
@@ -829,8 +829,7 @@ DEFER: initial-slot
 [ t ] [ initial-slot new x>> initial-class? ] unit-test
 
 [ "IN: classes.tuple.tests TUPLE: initial-slot { x initial-class initial: f } ;" eval( -- ) ]
-[ error>> T{ bad-initial-value f "x" } = ] must-fail-with
+[ error>> T{ bad-initial-value f "x" f initial-class } = ] must-fail-with
 
 [ "IN: classes.tuple.tests TUPLE: initial-slot { x initial-class initial: 3 } ;" eval( -- ) ]
-[ error>> T{ bad-initial-value f "x" } = ] must-fail-with
-
+[ error>> T{ bad-initial-value f "x" 3 initial-class } = ] must-fail-with
index 5d1dae2bd3672ed17d881b0d64eef8e310aac8a7..164c51f371d0572e867044eba0af53bf20aa2c09 100644 (file)
@@ -4,7 +4,7 @@ sequences strings tools.test vectors words quotations classes
 classes.private classes.union classes.mixin classes.predicate
 classes.algebra classes.union.private source-files
 compiler.units kernel.private sorting vocabs io.streams.string
-eval see math.private slots ;
+eval see math.private slots generic.single ;
 IN: classes.union.tests
 
 ! DEFER: bah
@@ -107,3 +107,28 @@ M: a-union test-generic ;
 [ ] [ "IN: classes.union.tests USE: vectors UNION: fast-union-1 vector ;" eval( -- ) ] unit-test
 
 [ f ] [ "fast-union-2?" "classes.union.tests" lookup-word def>> \ fixnum-bitand swap member? ] unit-test
+
+! Test union{
+
+TUPLE: stuff { a union{ integer string } } ;
+
+[ 0 ] [ stuff new a>> ] unit-test
+[ 3 ] [ stuff new 3 >>a a>> ] unit-test
+[ "asdf" ] [ stuff new "asdf" >>a a>> ] unit-test
+[ stuff new 3.4 >>a a>> ] [ bad-slot-value? ] must-fail-with
+
+TUPLE: things { a union{ integer float } } ;
+
+[ 0 ] [ stuff new a>> ] unit-test
+[ 3 ] [ stuff new 3 >>a a>> ] unit-test
+[ "asdf" ] [ stuff new "asdf" >>a a>> ] unit-test
+[ stuff new 3.4 >>a a>> ] [ bad-slot-value? ] must-fail-with
+
+PREDICATE: numba-ova-10 < union{ float integer }
+    10 > ;
+
+[ f ] [ 100/3 numba-ova-10? ] unit-test
+[ t ] [ 100 numba-ova-10? ] unit-test
+[ t ] [ 100.0 numba-ova-10? ] unit-test
+[ f ] [ 5 numba-ova-10? ] unit-test
+[ f ] [ 5.75 numba-ova-10? ] unit-test
index 6626ee685d63511c5f2306678b7b43ea7989bf95..ffc59e21a1de29b6f4ce8687d7eb84342a0a3dd2 100644 (file)
@@ -2,7 +2,7 @@
 ! See http://factorcode.org/license.txt for BSD license.
 USING: kernel math math.parser math.order namespaces make
 sequences strings words assocs combinators accessors arrays
-quotations ;
+quotations classes.algebra classes ;
 IN: effects
 
 TUPLE: effect
@@ -79,6 +79,7 @@ GENERIC: effect>type ( obj -- type )
 M: object effect>type drop object ;
 M: word effect>type ;
 M: pair effect>type second effect>type ;
+M: classoid effect>type ;
 
 : effect-in-types ( effect -- input-types )
     in>> [ effect>type ] map ;
index dc92c0705e781ca69fcd5fddeacda49da3261fea..2ba2f412cd532d5f7022a79cab620fb0a447862f 100644 (file)
@@ -3,7 +3,7 @@
 USING: accessors words kernel sequences namespaces make assocs
 hashtables definitions kernel.private classes classes.private
 classes.algebra quotations arrays vocabs effects combinators
-sets classes.maybe ;
+sets classes.maybe classes.algebra.private ;
 FROM: namespaces => set ;
 IN: generic
 
@@ -132,17 +132,21 @@ M: method crossref?
     [ method-word-name f <word> ] [ method-word-props ] 2bi
     >>props ;
 
-GENERIC: implementor-class ( obj -- class )
+GENERIC: implementor-classes ( obj -- class )
 
-M: maybe implementor-class class>> ;
+M: maybe implementor-classes class>> 1array ;
 
-M: class implementor-class ;
+M: class implementor-classes 1array ;
+
+M: anonymous-union implementor-classes members>> ;
+
+M: anonymous-intersection implementor-classes participants>> ;
 
 : with-implementors ( class generic quot -- )
-    [ swap implementor-class implementors-map get at ] dip call ; inline
+    [ swap implementor-classes [ implementors-map get at ] map ] dip call ; inline
 
-: reveal-method ( method class generic -- )
-    [ [ conjoin ] with-implementors ]
+: reveal-method ( method classes generic -- )
+    [ [ [ conjoin ] with each ] with-implementors ]
     [ [ set-at ] with-methods ]
     2bi ;
 
@@ -178,7 +182,7 @@ M: method forget*
                 ] keep eq?
                 [
                     [ [ delete-at ] with-methods ]
-                    [ [ delete-at ] with-implementors ] 2bi
+                    [ [ [ delete-at ] with each ] with-implementors ] 2bi
                     reset-caches
                 ] [ 2drop ] if
             ] if
index 5bb1630eb8deacd8f50ef73842b1ae0c19290f61..4c6731c93a640553b7ad60235e0c9b57c71295ba 100644 (file)
@@ -1,10 +1,10 @@
 ! Copyright (C) 2005, 2011 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: arrays byte-arrays kernel kernel.private math namespaces
-make sequences strings effects generic generic.standard
-classes classes.algebra slots.private combinators accessors
-words sequences.private assocs alien quotations hashtables
-classes.maybe ;
+USING: accessors alien arrays assocs byte-arrays classes
+classes.algebra classes.algebra.private classes.maybe
+combinators generic generic.standard hashtables kernel
+kernel.private make math quotations sequences sequences.private
+slots.private strings words ;
 IN: slots
 
 TUPLE: slot-spec name offset class initial read-only ;
@@ -151,13 +151,52 @@ M: object writer-quot
         [ define-changer ]
     } cleave ;
 
+DEFER: initial-value
+
 GENERIC: initial-value* ( class -- object ? )
 
 M: class initial-value* drop f f ;
 
+M: maybe initial-value*
+    drop f t ;
+
+! Default initial value is f, 0, or the default inital value
+! of the smallest class. Special case 0 because float is ostensibly
+! smaller than integer in union{ integer float } because of
+! alphabetical sorting.
+M: anonymous-union initial-value*
+    {
+        { [ f over instance? ] [ drop f t ] }
+        { [ 0 over instance? ] [ drop 0 t ] }
+        [
+            members>> sort-classes [ initial-value ] { } map>assoc
+            ?last [ second t ] [ f f ] if*
+        ]
+    } cond ;
+
+! See if any of the initial values fit the intersection class,
+! or else return that none do, and leave it up to the user to provide
+! an initial: value.
+M: anonymous-intersection initial-value*
+    {
+        { [ f over instance? ] [ drop f t ] }
+        { [ 0 over instance? ] [ drop 0 t ] }
+        [
+            [ ]
+            [ participants>> sort-classes [ initial-value ] { } map>assoc ]
+            [ ] tri
+
+            [ [ first2 nip ] dip instance? ] curry find swap [
+                nip second t
+            ] [
+                2drop f f
+            ] if
+        ]
+    } cond ;
+
 : initial-value ( class -- object ? )
     {
-        { [ dup maybe? ] [ f t ] }
+        { [ dup only-classoid? ] [ dup initial-value* ] }
         { [ dup "initial-value" word-prop ] [ dup "initial-value" word-prop t ] }
         { [ \ f bootstrap-word over class<= ] [ f t ] }
         { [ \ array-capacity bootstrap-word over class<= ] [ 0 t ] }
@@ -202,12 +241,16 @@ ERROR: bad-slot-attribute key ;
         } case
     ] unless ;
 
-ERROR: bad-initial-value name ;
+ERROR: bad-initial-value name initial-value class ;
 
 : check-initial-value ( slot-spec -- slot-spec )
     [ ] [
-        dup [ initial>> ] [ class>> ] bi instance?
-        [ name>> bad-initial-value ] unless
+        [ ] [ initial>> ] [ class>> ] tri
+        2dup instance? [
+            2drop
+        ] [
+            [ name>> ] 2dip bad-initial-value
+        ] if
     ] if-bootstrapping ;
 
 M: array make-slot
index b4c2c5b065818bf84975bd98a25afff4c55f1591..c780abe0eb4edd0324b73e67be9df31d7ed06fb9 100644 (file)
@@ -8,7 +8,8 @@ generic.standard generic.hook generic.math generic.parser classes
 io.pathnames vocabs vocabs.parser classes.parser classes.union
 classes.intersection classes.mixin classes.predicate
 classes.singleton classes.tuple.parser compiler.units classes.maybe
-combinators effects.parser slots hash-sets source-files ;
+combinators effects.parser slots hash-sets source-files
+classes.algebra.private ;
 IN: bootstrap.syntax
 
 ! These words are defined as a top-level form, instead of with
@@ -252,7 +253,15 @@ IN: bootstrap.syntax
     "maybe:" [
         scan-class <maybe> suffix!
     ] define-core-syntax
-    
+
+    "intersection{" [
+         \ } [ <anonymous-intersection> ] parse-literal
+    ] define-core-syntax
+
+    "union{" [
+        \ } [ <anonymous-union> ] parse-literal
+    ] define-core-syntax
+
     "initial:" "syntax" lookup-word define-symbol
 
     "read-only" "syntax" lookup-word define-symbol