duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit f440785490b4da379d7d4ea3b6bf704834d64d06
parent 1a8c9e834a6a38c3c79fd8e6124e550702a0b764
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Mon, 15 May 2023 21:01:13 -0400

Introduce new ":[methods]" pattern in structures

See doc/struct. This new pattern doesn't improve code density (the opposite in
fact), but it allows to avoid painful code repetition, with the worst offender
being the IO struct. Whenever the structure of those structs that are widely
extended would change, one would have to go modify all extending structs.

Not anymore.

Diffstat:
Mfs/doc/dict.txt | 4++++
Mfs/doc/struct.txt | 88++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mfs/drv/fbgrid/fbgrid.fs | 5+----
Mfs/drv/pc/com.fs | 7+++----
Mfs/drv/pc/vesa.fs | 20++++++++------------
Mfs/drv/pc/vga.fs | 7+------
Mfs/fs/fat.fs | 19++++++++-----------
Mfs/fs/fatlo.fs | 41++++++++++++++++++++---------------------
Mfs/gr/plane.fs | 6++++--
Mfs/lib/file.fs | 35++++++++++++++++++-----------------
Mfs/sys/grid.fs | 4+++-
Mfs/sys/io.fs | 20++++++++++----------
Mfs/sys/rdln.fs | 4++--
Mfs/sys/screen.fs | 7+++----
Mfs/tests/kernel.fs | 11+++++++++++
Mfs/text/ed.fs | 12++++++------
Mfs/xcomp/bootlo.fs | 52++++++++++++++++++++++++++++++++++------------------
Mposix/glue.fs | 26++++++++++++--------------
18 files changed, 235 insertions(+), 133 deletions(-)

diff --git a/fs/doc/dict.txt b/fs/doc/dict.txt @@ -154,11 +154,14 @@ allot0 u -- Allot u and fill this space with zeroes. move src dst u -- Copy u bytes from address src to address dst, moving upwards. move, src u -- Copy u bytes to "here" and increase "here" by u. +-move, src u -- Rewind "here" by u, then call "move,". fill a u c -- Fill range [a, a+u] with byte c. align4 n -- Allot 0, 1, 2 or 3 bytes so that "here+n" is divisible by 4. nc, n -- Parse n numbers from input stream and write them as 8-bit values. +nabort, n -- Write address of word "abort" n times. Used for method + placeholders. [c]? c a u -- i Search for character c in range [a, a+u] and yield its index or -1 if not found. @@ -268,6 +271,7 @@ find name 'dict -- word-or-0 match was found. ' "x" -- w Find x in system dictionary and error out if not found. ['] "x" -- *I* Find x and compile its address as a literal. +'" "x" -- *I* Compile x as a string followed by a call to '. w>e w -- e Yield an entry (linked list pointer) from a word reference. e>w e -- w Yield a word reference (executable) from an entry. entry 'dict s -- diff --git a/fs/doc/struct.txt b/fs/doc/struct.txt @@ -163,11 +163,97 @@ Warning: do not augment a struct with new fields if it has already been extended by another struct because this will generate slot conflicts. You can augment a struct that has been extended, that will work, but only with non-field words. -## Name conventions +## Structure conventions + +What is described above is the structure mechanism. That's how it works. If you +look at how structures are used in Dusk OS, you'll see some patterns emerge that +aren't described above. Those are conventions. You don't have to follow them in +your own code, but if you want to interact with Dusk structures, you need to +know about them. A structure begins with an uppercase letter and a word in a namespace that is intended to be called from the outside (so, not only methods) begin with a ":". +A structure "constructor" has the name ":new". Is is expected to consume +initialization arguments from PS and yield a single element: the address of the +created structure. + +Structure allocation is often made directly to "here" (with dynamic allocation +details left to the caller), but not always. + +When a structure extends another, it's common practive for the extending struct +to call its base struct's ":new" method and add to it. + +Structure methods initialization is a bit tricky. The whole point of those +methods is to allow a structure that extends another structure to override them. +For this to be done harmoniously, the "extender" struct, at *compile* time, +needs to make a list of those methods it want to write, and overwrite the +methods that were written by the base struct. For simplicity, this is often done +using a combination of "S[" and "-move,". Example: + + struct[ MyAbstract + smethod :foo + : :new here ['] abort , ; + ]struct + extends MyAbstract struct[ MyImpl + sfield myfield + : impl drop 42 ; + : :new MyAbstract :new S[ ' impl , ]S c@+ -move, 54 ( myfield ) , ; + ]struct + MyImpl :new dup :foo . \ prints 42 + myfield . \ prints 54 + +For this to work, methods need to be the last fields of the struct (but +"extenders" can add other fields on top of it), which is another convention that +Dusk OS follows. + +Because the pattern above requires every struct "extender" to repeat the name +of the methods and because this is tedious and verbose, another convention +emerges from that: Method implementations have the name of the method, minus the +":" prefix, and base structs have a ":[methods]" word that dynamically look for +those names and write them. Then, "extenders" call this method at compile time +and write this string down in their ":new" implementation. This results in code +that looks like this: + + struct[ MyAbstract + smethod :foo + : :new here ['] abort , ; + : :[methods] '" foo" , ; + ]struct + extends MyAbstract struct[ MyImpl + sfield myfield + : foo drop 42 ; + : :new MyAbstract :new S[ :[methods] , ]S c@+ -move, 54 ( myfield ) , ; + ]struct + +With one "extender", the gain is slim (null in fact), but as extenders multiply, +this patterns allows us to minimize code duplication and make changes in base +structures much easier. + +Note that this pattern only works for direct extension overrides (the most +frequent case). If a struct extender needs to override a method from a structure +more than 1 level deep in the hierarchy, the pattern is a bit more complex and +involves base structures creating a "METHSZ" constant. Here's an example: + + struct[ A + sfield a + SZ &+ :methods( + smethod :foo + : :new here 0 ( a ) , ['] abort , ; + : :[methods] '" foo" , ; + ]struct + extends A struct[ B + sfield b + : :new A :new 0 ( b ) , ; + ]struct + extends B struct[ C + sfield c + : :new B :new 0 ( c ) , + S[ A :[methods] ]S c@+ dip over A :methods( | move ; + ]struct + +So, a bit more verbose than the direct variant, but it happens much less often. + ## API struct[ "name" -- Create a struct named "name" and enter its definition diff --git a/fs/drv/fbgrid/fbgrid.fs b/fs/drv/fbgrid/fbgrid.fs @@ -73,10 +73,7 @@ extends Grid struct[ FbGrid repeat rdrop rdrop rdrop ; : :new ( -- grid ) screen width 8 / screen height 8 / Grid :new - ['] cell! over ['] :cell! sfield! - ['] cursor! over ['] :cursor! sfield! - ['] newln over ['] :newln sfield! - ['] highlight over ['] :highlight sfield! ; + S[ :[methods] ]S c@+ -move, ; ]struct : fbgrid$ screen :activate FbGrid :new ['] grid rebind diff --git a/fs/drv/pc/com.fs b/fs/drv/pc/com.fs @@ -19,10 +19,9 @@ $3f8 const COMPORT extends IO struct[ COM1 create _buf 0 c, - : _readbuf ( n self -- a? read-n ) + : readbuf ( n self -- a? read-n ) 2drop com>? if _buf tuck c! 1 else 0 then ; - : _writebuf ( a n self -- written-n ) - 2drop c@ >com 1 ; - : :new here 0 , ['] _readbuf , ['] _writebuf , ['] drop dup , , ; + : writebuf ( a n self -- written-n ) 2drop c@ >com 1 ; + : :new IO :new S[ :[methods] ]S c@+ -move, ; ]struct COM1 :new structbind COM1 com1 diff --git a/fs/drv/pc/vesa.fs b/fs/drv/pc/vesa.fs @@ -102,7 +102,7 @@ $111 value vesamode extends Screen struct[ VESA2Screen \ for VBE2 \ Here, we deal only with linear modes - : _activate ( self -- ) + : activate ( self -- ) vesamode _modeinfo dup VBEModeInfo :linear? _assert ( mode ) _curmode :self VBEModeInfo SZ move 0 vesamode $4000 or $4f02 int10h ( self bx ax ) @@ -112,12 +112,10 @@ extends Screen struct[ VESA2Screen \ for VBE2 _curmode pitch over to pitch _curmode framebuffer swap to buffer ; - : _deactivate ( self -- ) 0 to buffer vgatext! ; + : deactivate ( self -- ) 0 to buffer vgatext! ; : :new ( -- screen ) - 0 0 COLOR_RGB565 Screen :new ( screen ) - ['] _activate over ['] :activate sfield! - ['] _deactivate over ['] :deactivate sfield! ; + 0 0 COLOR_RGB565 Screen :new ( screen ) S[ :[methods] ]S c@+ -move, ; ]struct $a0000 const VESABANK \ for nonlinear modes, the address of the 64K bank @@ -130,7 +128,7 @@ extends Screen struct[ VESA1Screen \ for VBE1.2 0 value bank \ currently activated bank 1 value bankmult - : _activate ( self -- ) + : activate ( self -- ) vesamode _modeinfo dup VBEModeInfo :linear? not _assert dup VBEModeInfo winfuncptr _assert ( mode ) _curmode :self VBEModeInfo SZ move @@ -142,19 +140,17 @@ extends Screen struct[ VESA1Screen \ for VBE1.2 $40 _curmode granularity / to bankmult VESABANK swap to buffer ; - : _deactivate ( self -- ) 0 to buffer vgatext! ; + : deactivate ( self -- ) 0 to buffer vgatext! ; : _bank! ( n -- ) dup bankmult * 0 $4f05 int10h 2drop ( dup 1 $4f05 int10h 2drop ) to bank ; : _?bank! ( off -- ) 16 rshift dup bank = if drop else _bank! then ; - : _xyoffbank ( x y self -- n ) _xyoff dup _?bank! $ffff and ; + : xyoff ( x y self -- n ) Plane xyoff dup _?bank! $ffff and ; : :new ( -- screen ) 0 0 COLOR_RGB565 Screen :new ( screen ) - 0 ( bank ) , - ['] _activate over ['] :activate sfield! - ['] _deactivate over ['] :deactivate sfield! - ['] _xyoffbank over ['] :xyoff sfield! ; + S[ :[methods] ]S c@+ -move, 0 ( bank ) , + S[ Plane :[methods] ]S c@+ dip over Plane :methods( | move ; ]struct diff --git a/fs/drv/pc/vga.fs b/fs/drv/pc/vga.fs @@ -19,12 +19,7 @@ extends Grid struct[ VgaGrid create _tbl $f , $7f , : highlight ( f pos -- ) << _mem( + 1+ swap bool CELLSZ * _tbl + @ swap c! ; - : :new ( -- grid ) - _COLS _LINES Grid :new - ['] cell! over ['] :cell! sfield! - ['] cursor! over ['] :cursor! sfield! - ['] newln over ['] :newln sfield! - ['] highlight over ['] :highlight sfield! ; + : :new ( -- grid ) _COLS _LINES Grid :new S[ :[methods] ]S c@+ -move, ; ]struct \ Set video mode to text mode, 80x25 diff --git a/fs/fs/fat.fs b/fs/fs/fat.fs @@ -113,12 +113,12 @@ $e5 const DIRFREE r> findfreedirentry dup DirEntry SZ 0 fill ( direntry ) fnbuf( over DirEntry NAMESZ move ( direntry ) ; -:realias :newfile ( dirid name self -- id ) >r +:realias newfile ( dirid name self -- id ) >r r@ _newentry ( dirent ) r@ writecursector r> :getid ; : _makedir ( dirent -- dirent ) $10 over to DirEntry attr ; -:realias :newdir ( dirid name self -- id ) +:realias newdir ( dirid name self -- id ) r! allocatecluster0 >r ( dirid name ) \ V1=self V2=cluster V1 _newentry ( dirent ) _makedir ( dirent ) V2 over to DirEntry cluster V1 writecursector ( dirent ) @@ -142,10 +142,10 @@ $e5 const DIRFREE swap r@ :FirstSectorOfCluster ( dst sec ) swap r@ secpercluster swap r> writesectors ; -:realias :info ( id self -- info ) FATInfo :read ; +:realias info ( id self -- info ) FATInfo :read ; \ TODO: deallocate the chain before clearing the entry -:realias :remove ( id self -- ) +:realias remove ( id self -- ) tuck :getdirentry ( dirent ) DIRFREE swap c! writecursector ; \ Read next sector if a sequential read is available, else return false. @@ -159,7 +159,7 @@ $e5 const DIRFREE dup DirEntry :lastentry? if drop 0 else dup DirEntry :iterable? not if V1 _next then then ( entry ) rdrop ; -:realias :iter ( dirid previd self -- id-or-0 ) >r >r \ V1=self V2=previd +:realias iter ( dirid previd self -- id-or-0 ) >r >r \ V1=self V2=previd V1 :getdirentry V1 :readdir V1 :dirwin :buf( DirEntry SZ - V2 if begin ( entry ) V1 _next dup while dup V1 :getid V2 <> while repeat then then ( entry-or-0 ) dup if V1 _next dup if V1 :getid then then 2rdrop ; @@ -204,7 +204,7 @@ create _FATTemplate ]struct struct+[ FATFile - : _flush ( hdl -- ) + :realias flush ( hdl -- ) r! :dirty? not if rdrop exit then ( ) \ save buffer r@ cluster r@ :buf( r@ :fat writecluster ( ) @@ -213,7 +213,6 @@ struct+[ FATFile r@ :fat writecursector \ undirty the cursor r@ flags $fffffffd and to r> flags ; - current ' :flush realias \ grow fcursor to newsz, if needed : _grow ( newsz self -- ) @@ -227,7 +226,7 @@ struct+[ FATFile V1 size V1 :fat :ClusterSize / ?dup if for ( cluster ) V1 :fat FAT@+ next then ( cluster ) drop rdrop ; - : _writebuf ( buf n self -- n ) + :realias writebuf ( buf n self -- n ) dup :free? if 2drop drop 0 exit then ( buf n self ) r! pos over + r@ _grow ( src n ) \ TODO: this seek below doesn't seem right. The buffer should be at all times @@ -237,13 +236,11 @@ struct+[ FATFile r@ :)buf r@ :ptr - ( src n nmax ) min ( src n ) r@ :ptr swap ( src dst n ) r! move r> ( n ) r@ pos over + r> :seek ; - current ' :writebuf realias \ TODO: deallocate truncated FATs if appropriate - : _truncate ( self -- ) + :realias truncate ( self -- ) dup pos ( self pos ) 2dup swap to size ( self pos ) over :dirent to DirEntry filesize ( self ) :fat writecursector ; - current ' :truncate realias ]struct diff --git a/fs/fs/fatlo.fs b/fs/fs/fatlo.fs @@ -137,7 +137,7 @@ $18 const HDRSZ swap r@ :FirstSectorOfCluster ( dst sec ) swap r@ secpercluster swap r> :readsectors ; -: :child ( dirid name self -- id-or-0 ) >r +: child ( dirid name self -- id-or-0 ) >r fnbuf! r@ :getdirentry r@ :readdir r@ :findindir dup if r@ :getid then rdrop ; ]struct @@ -162,15 +162,15 @@ extends File struct[ FATFile : :dirent ( self -- dirent ) bi entryoff | :fat :getdirentry ; : :cluster0 ( self -- cl ) :dirent DirEntry cluster ; - alias abort :writebuf - alias drop :flush - alias abort :truncate + alias abort writebuf + alias drop flush + alias abort truncate : _poscluster ( self -- idx ) bi pos | bufsz / ; : _inbounds? ( self -- f ) bi _poscluster | clusteridx = ; \ set self to pos. If new pos crosses cluster boundaries compared to current \ pos, flush current buffer and read a new sector from disk. - : :seek ( pos self -- ) + : seek ( pos self -- ) dup :free? if 2drop exit then >r ( pos ) \ V1=self dup 0< if abort" can't seek to negative pos" then V1 to pos V1 _inbounds? not if @@ -178,7 +178,7 @@ extends File struct[ FATFile V1 :cluster0 ( idx cl ) swap for ( cl ) V1 :fat :FAT@ next ( cl ) dup V1 :buf( V1 :fat :readcluster ( cl ) V1 to cluster then rdrop ; - : :readbuf ( n self -- a? n ) + : readbuf ( n self -- a? n ) dup :free? if 2drop 0 exit then ( n self ) bi+ size | pos - ( n self maxn ) dup 1- 0< if ( EOF ) 2drop drop 0 exit then swap >r ( n maxn ) \ V1=self @@ -187,19 +187,19 @@ extends File struct[ FATFile r@ :ptr r@ :)buf over - ( n a nmax ) rot min ( a n ) dup r> to+ pos ( a n ) ; - : :close ( self -- ) dup :flush :release ; + : close ( self -- ) dup :flush :release ; : :open ( direntry self -- ) r! :hold dup V1 :fat :getid ( dirent entryoff ) \ V1=self r@ to entryoff DirEntry filesize r@ to size ( ) 0 to r@ pos -1 to r> clusteridx ; : :new ( fat -- hdl ) - 0 align4 dup to' FAT lastcursor lladd ( fat newll ) drop here >r - 0 ( putback ) , ['] :readbuf , ['] :writebuf , ['] :flush , ['] :close , - 0 ( pos ) , 0 ( size ) , 0 ( bufptr ) , dup FAT :ClusterSize ( bufsz ) , - ['] :seek , ['] :truncate , ( fat ) , 0 ( flags ) , 0 ( cluster ) , + 0 align4 dup to' FAT lastcursor lladd drop ( fat ) + File :new >r S[ :[methods] ]S c@+ -move, ( fat ) \ V1=hdl + S[ IO :[methods] ]S c@+ r@ IO :methods( swap move + dup ( fat ) , 0 ( flags ) , 0 ( cluster ) , -1 ( clusteridx ) , 0 ( entryoff ) , - here r@ to bufptr r@ bufsz allot r> ; + here r@ to bufptr FAT :ClusterSize dup allot r@ to bufsz r> ; ]struct struct+[ FAT @@ -208,21 +208,20 @@ struct+[ FAT ?dup while dup CELLSZ + FATFile :free? not while llnext repeat nip CELLSZ + else FATFile :new then ; - : :open ( id self -- hdl ) + : open ( id self -- hdl ) tuck :getdirentry swap :findfreecursor ( dirent hdl ) tuck FATFile :open ; - alias abort :info - alias abort :iter - alias abort :newfile - alias abort :newdir - alias abort :remove + alias abort info + alias abort iter + alias abort newfile + alias abort newdir + alias abort remove : :mountvolume ( drv -- fs ) dup SectorWindow :new over SectorWindow :new rot - here >r ( fatwin dirwin rot ) \ V1=fs - dup , 0 ( flags ) , ['] :child , ['] :info , ['] :open , - ['] :iter , ['] :newfile , ['] :newdir , ['] :remove , + dup Filesystem :new >r ( fatwin dirwin drv ) \ V1=fs + S[ :[methods] ]S c@+ -move, 0 ( bufcluster ) , 0 ( lastcursor ) , rot ( fatwin ) , swap ( dirwin ) , \ At this point, "here" points to the FAT-header-to-be. Read the first sector \ directly in "here": we'll have the header right here! diff --git a/fs/gr/plane.fs b/fs/gr/plane.fs @@ -13,11 +13,12 @@ extends Rect struct[ Plane sfield ty sfield color sfield buffer + SZ &+ :methods( smethod :xyoff ( x y self -- n ) : _colorbytes ( id -- nbytes ) colorbpp >> >> >> ; - : _xyoff ( x y self -- n ) + : xyoff ( x y self -- n ) tuck pitch * rot> encoding _colorbytes * + ; : _addr ( self -- a ) @@ -26,7 +27,8 @@ extends Rect struct[ Plane : :new ( width height encoding -- plane ) >r >r >r 0 0 r> r> Rect :new ( rect ) r> ( encoding ) dup , _colorbytes over Rect width * ( pitch ) , - 0 ( tx ) , 0 ( ty ) , 0 ( color ) , 0 ( buffer ) , ['] _xyoff , ; + 0 ( tx ) , 0 ( ty ) , 0 ( color ) , 0 ( buffer ) , ['] xyoff , ; + : :[methods] '" xyoff" , ; : :allotbuf ( self -- ) >r \ V1=self here r@ pitch r@ height * allot r> to buffer ; diff --git a/fs/lib/file.fs b/fs/lib/file.fs @@ -2,36 +2,37 @@ extends File struct[ MemFile : _maxn ( n hdl -- real-n ) >r V1 pos + V1 size min r> pos - ; - : _readbuf ( n hdl -- a? read-n ) + : readbuf ( n hdl -- a? read-n ) >r V1 _maxn ( read-n ) dup if V1 :ptr swap dup V1 to+ pos then rdrop ; - : _writebuf ( a n hdl -- written-n ) + : writebuf ( a n hdl -- written-n ) >r V1 _maxn ( a write-n ) dup if ( a write-n ) tuck V1 :ptr swap ( write-n a dst n ) move ( write-n ) dup V1 to+ pos else nip then rdrop ; - : _seek ( pos hdl -- ) to pos ; - : :new ( sz -- hdl ) here swap ( hdl sz ) - 0 ( putback ) , ['] _readbuf , ['] _writebuf , ['] drop , ['] drop , - 0 ( pos ) , dup ( size ) , over SZ + ( bufptr ) , dup ( bufsz ) , - ['] _seek , ( sz ) allot ; + : seek ( pos hdl -- ) to pos ; + alias drop truncate + : :new ( sz -- hdl ) + File :new >r S[ :[methods] ]S c@+ -move, ( sz ) \ V1=hdl + S[ IO :[methods] ]S c@+ r@ IO :methods( swap move + dup to r@ size dup to r@ bufsz here to r@ bufptr allot r> ; ]struct extends File struct[ DriveFile sfield secwin : :secwin [compile] secwin [compile] SectorWindow ; immediate - : _flush :secwin :flush ; - : _seek ( pos self -- ) to pos ; - : _readbuf ( n self -- a? read-n ) + : flush :secwin :flush ; + : seek ( pos self -- ) to pos ; + : readbuf ( n self -- a? read-n ) over if swap >r bi+ pos | :secwin :seek ( self a? n ) r> min dup if rot over swap to+ pos then else drop then ; - : _writebuf ( a n self -- written-n ) - r! _readbuf ( src dst? n ) dup if + : writebuf ( a n self -- written-n ) + r! readbuf ( src dst? n ) dup if r! move r> r> :secwin :dirty! else nip rdrop then ; + alias drop truncate : :new ( drv -- hdl ) - SectorWindow :new here ( secwin hdl ) - 0 ( putback ) , ['] _readbuf , ['] _writebuf , ['] _flush , ['] drop , - 0 ( pos ) , -1 ( size ) , over SectorWindow :buf( ( bufptr ) , - over SectorWindow :drv secsz ( bufsz ) , ['] _seek , ['] drop ( truncate ) , - swap ( secwin ) , dup 0 -1 rot :secwin :move ; + SectorWindow :new File :new >r S[ :[methods] ]S c@+ -move, ( secwin ) , + S[ IO :[methods] ]S c@+ r@ IO :methods( swap move + -1 to r@ size r@ :secwin :buf( to r@ bufptr + r@ :secwin :drv secsz to r@ bufsz 0 -1 r@ :secwin :move r> ; ]struct diff --git a/fs/sys/grid.fs b/fs/sys/grid.fs @@ -39,9 +39,11 @@ extends ByteWriter struct[ Grid : :spitoff ( self -- ) ['] _emit swap ['] :writebyte sfield! ; + alias 2drop highlight + : :[methods] '" cell!" , '" cursor!" , '" newln" , '" highlight" , ; : :new ( cols lines -- grid ) ['] _emit ByteWriter :new rot ( cols ) , swap ( lines ) , 0 , 0 , - ['] abort , ['] abort , ['] abort , ['] 2drop , ; + 4 nabort, ; : _dbgnum! ( n pos self -- ) tuck :spiton tuck :.x :spitoff ; diff --git a/fs/sys/io.fs b/fs/sys/io.fs @@ -48,14 +48,14 @@ extends IO struct[ SumIO sfield fn sfield res - : _writebuf ( a n hdl -- written-n ) + alias _ioerr readbuf + : writebuf ( a n hdl -- written-n ) dup >r fn >r swap >r dup >r V1 res for ( n r ) \ V1=hdl V2=fn V3=a 8b to@+ V3 V2 execute next ( n r ) V1 to res 2rdrop 2rdrop ( written-n ) ; \ fn sig: ( sum c -- sum ) - : :new ( 'fn -- hdl ) here swap ( hdl 'fn ) - 0 ( putback ) , ['] _ioerr , ['] _writebuf , ['] drop , ['] drop , - ( 'fn ) , 0 , ; + : :new ( 'fn -- hdl ) + IO :new S[ :[methods] ]S c@+ -move, swap ( 'fn ) , 0 , ; ]struct extends IO struct[ MemIO @@ -64,9 +64,9 @@ extends IO struct[ MemIO sfield ptr : _bounds ( n hdl -- n ) dup )buf swap ptr - min ; - : _readbuf ( n hdl -- a? read-n ) >r \ V1=self + : readbuf ( n hdl -- a? read-n ) >r \ V1=self V1 _bounds dup if r@ ptr swap dup to+ r> ptr else rdrop then ; - : _writebuf ( a n hdl -- written-n ) >r \ V1=self + : writebuf ( a n hdl -- written-n ) >r \ V1=self V1 _bounds dup if ( a n ) dup >r V1 ptr ( src n dst ) swap move \ V2=n r> dup r> ( n n hdl ) to+ ptr ( written-n ) @@ -75,17 +75,17 @@ extends IO struct[ MemIO : :eof? dup )buf swap ptr = ; : :rewind ( hdl -- ) dup buf( swap to ptr ; : :new ( a u -- hdl ) - here >r 0 ( putback ) , ['] _readbuf , ['] _writebuf , ['] drop , ['] drop , + IO :new >r S[ :[methods] ]S c@+ -move, over , over + , , r> ; ]struct extends IO struct[ ByteWriter smethod :writebyte ( c self -- ) - : _writebuf ( a n self -- written-n ) >r dup >r \ V1=self V2=n + alias _ioerr readbuf + : writebuf ( a n self -- written-n ) >r r! \ V1=self V2=n for ( a ) c@+ V1 :writebyte next drop r> rdrop ; : :new ( writebyte -- writer ) - here 0 ( putback ) , ['] _ioerr , ['] _writebuf , ['] drop , ['] drop , - swap ( writebyte ) , ; + IO :new S[ :[methods] ]S c@+ -move, swap ( writebyte ) , ; ]struct diff --git a/fs/sys/rdln.fs b/fs/sys/rdln.fs @@ -23,10 +23,10 @@ extends MemIO struct[ Rdln begin key V1 :lntype until V1 ptr V1 to )buf V1 :rewind r> )buf 1- c@ ESC <> ; : _readbuf2 ( n hdl -- a? read-n ) - dup :eof? if begin ." ok\n" dup :typeline until nl> then _readbuf ; + dup :eof? if begin ." ok\n" dup :typeline until nl> then readbuf ; : :reset ['] _readbuf2 over ['] :readbuf sfield! dup )buf swap to ptr ; : :interpret - ['] _readbuf over ['] :readbuf sfield! + ['] readbuf over ['] :readbuf sfield! MemIO :interpret :reset ; : :new MemIO :new dup :reset ; ]struct diff --git a/fs/sys/screen.fs b/fs/sys/screen.fs @@ -6,11 +6,10 @@ extends Plane struct[ Screen smethod :deactivate ( self -- ) smethod :activated? ( self -- f ) - : _activated? ( self -- f ) buffer bool ; - + : activated? ( self -- f ) buffer bool ; : :new ( width height encoding -- screen ) - Plane :new ( screen ) - ['] abort , ['] abort , ['] _activated? , ; + Plane :new ( screen ) S[ :[methods] ]S c@+ -move, 3 nabort, ; + : :[methods] '" activate" , '" deactivate" , '" activated?" , ; ]struct 0 structbind Screen screen diff --git a/fs/tests/kernel.fs b/fs/tests/kernel.fs @@ -158,4 +158,15 @@ extends Foo struct[ Bazooka create data3 7 , 9 c, ' mybleh , 999 , data3 Bazooka bling 999 #eq data3 Bazooka baz 9 #eq + +\ Test abstract method override mechanism +struct[ MyAbstract + smethod :foo + : :[new] '" foo" , ; +]struct +extends MyAbstract struct[ MyImpl + : foo drop 42 ; + : :new here S[ MyAbstract :[new] ]S c@+ move, ; +]struct +MyImpl :new MyAbstract :foo 42 #eq testend diff --git a/fs/text/ed.fs b/fs/text/ed.fs @@ -84,7 +84,7 @@ extends IO struct[ Edbuf : :lastline? bi :lpos | :linecnt 1- = ; : _eof? ( self -- f ) bi :lastline? | _eol? and ; create _lf LF c, - : _readbuf ( n self -- a? read-n ) >r ( n ) \ V1=self + : readbuf ( n self -- a? read-n ) >r ( n ) \ V1=self r@ _eof? if rdrop drop 0 exit then r@ _eol? if drop 1 r@ :godown 0 r> _cpos! _lf 1 exit then r@ :sel Line cnt r@ :cpos - ( n1 n2 ) @@ -101,7 +101,7 @@ extends IO struct[ Edbuf tuck V1 :cpos V2 Line :insert ( u ) rdrop r> to+ pos ; - : _writebuf ( a n self -- written-n ) >r \ V1=self + : writebuf ( a n self -- written-n ) >r \ V1=self 2dup LF rot> [c]? ( a u idx ) dup 0< if drop tuck r> _writeline ( written-n ) else ( a u idx ) @@ -128,11 +128,11 @@ extends IO struct[ Edbuf lpos V1 :lpos V1 :sel Line cnt bool + ( linehi linelo ) tuck - 1+ swap V1 lines Array :delete V1 _ensureline then rdrop ; + alias :empty close : :new ( -- edbuf ) - Arena :new Line SZ $200 Array :new here ( arena lines edbuf ) >r - 0 ( putback ) , ['] _readbuf , ['] _writebuf , ['] drop , ['] :empty , - swap ( arena ) , ( lines ) , 0 ( pos ) , - r> dup :empty ; + Arena :new Line SZ $200 Array :new + IO :new S[ :[methods] ]S c@+ -move, ( arena lines edbuf ) + rot ( arena ) , swap ( lines ) , 0 ( pos ) , dup :empty ; : :goleft ( n self -- ) dup :cpos rot - max0 swap _cpos! ; : :goright ( n self -- ) dup :cpos rot + over _cpos! _cbounds ; diff --git a/fs/xcomp/bootlo.fs b/fs/xcomp/bootlo.fs @@ -253,23 +253,25 @@ alias drop emit : nl> LF emit ; : spc> SPC emit ; :realias rtype ( a u ) for c@+ emit next drop ; : stype ( str -- ) c@+ rtype ; -create _escapes 'n' c, 'r' c, '0' c, -create _repl LF c, CR c, 0 c, +create _escapes 3 nc, 'n' 'r' '0' +create _repl 3 nc, LF CR 0 : "< ( -- c ) in< dup '"' = if drop -1 else dup '\' = if drop in< dup _escapes 3 [c]? dup 0>= if nip _repl + c@ else drop then then then ; : ," begin "< dup -1 <> while c, repeat drop ; code (s) r@ W>A, W) 8b) @, 1 W+n, RSP) +, rdrop W<>A, branchA, -: _S compiling if compile (s) else here then here 1 allot here ; -: S[ _S [compile] [ ; immediate -: ]S ( str -- ) here -^ ( 'len len ) swap c! ; -: S" _S ," [compile] ]S ; immediate +: _S[ compiling if compile (s) else here then here 1 allot here ; +: S[ _S[ [compile] [ ; immediate +: _]S ( str -- ) here -^ ( 'len len ) swap c! ; +: ]S _]S ] ; +: S" _S[ ," _]S ; immediate : ." compiling if [compile] S" compile stype else begin "< dup 0>= while emit repeat drop then ; immediate : abort" [compile] ." compile abort ; immediate : word" [compile] S" NEXTWORD litn compile ! ; immediate +: '" [compile] word" compile ' ; immediate code []= ( a1 a2 u -- f ) W=0>Z, 0 Z) branchC, PSP) @!, W>A, begin \ P+4=a1 P+0=u A=a2 @@ -289,6 +291,7 @@ code move ( src dst u -- ) 8 ps+, drop, exit, : move, ( src u -- ) here swap dup allot move ; +: -move, ( src u -- ) here over - swap move ; \ Structures 0 value _extends @@ -321,7 +324,7 @@ code move ( src dst u -- ) else word" :self" code exit, \ :self is our root sysdict @ to _curroot then - word" SZ" code _cur e>w structsz' litn compile @ exit, + word" SZ" code _cur e>w structsz' litn W) @, exit, does> ( 'struct ) _structfind dup 1- c@ $80 and not compiling and \ compile only if not immediate @@ -361,11 +364,12 @@ create _ 0 , EMETA_8B , EMETA_16B , does> CELLSZ + @ over + @ execute ; : ssmethod doer CELLSZ STRUCTFIELD_STATICMETHOD _sfield does> CELLSZ + @ swap + @ execute ; +: nabort, ( n -- ) ['] abort swap for dup , next drop ; \ 4b link to struct \ 4b link to data : structbind ( 'data -- ) ' doer , , immediate does> ( 'bind -- *to* ) - @+ swap compiling if litn compile @ else @ swap then execute ; + @+ swap compiling if dup, m) @, else @ swap then execute ; : rebind ( 'data 'bind -- ) does' CELLSZ + ! ; struct[ Drive @@ -373,10 +377,13 @@ struct[ Drive sfield seccnt smethod :sec@ ( sec dst drv -- ) smethod :sec! ( sec src drv -- ) + : :new ( secsz seccnt -- drv ) here rot , swap , ; + : :[methods] '" sec@" , '" sec!" , ; ]struct struct[ IO sfield putback + SZ &+ :methods( smethod :readbuf ( n hdl -- a? read-n ) smethod :writebuf ( a n hdl -- written-n ) smethod :flush ( hdl -- ) @@ -384,23 +391,25 @@ struct[ IO : :getc ( hdl -- c ) dup putback ?dup if ( hdl c ) 0 rot to putback else ( hdl ) 1 swap :readbuf if c@ else -1 ( EOF ) then then ; + : :new here 0 ( putback ) , 4 nabort, ; + alias drop close + alias drop flush + : :[methods] '" readbuf" , '" writebuf" , '" flush" , '" close" , ; ]struct extends IO struct[ Pipe sfield readio sfield writeio - : _readbuf readio :readbuf ; - : _writebuf writeio :writebuf ; - : _flush writeio :flush ; + : readbuf readio :readbuf ; + : writebuf writeio :writebuf ; + : flush writeio :flush ; : :new ( readio writeio -- pipe ) - here 0 , ['] _readbuf , ['] _writebuf , ['] _flush , ['] drop , - rot ( readio ) , swap ( writeio ) , ; + IO :new S[ :[methods] ]S c@+ -move, rot ( readio ) , swap ( writeio ) , ; : _chain! ( w1 'w2 -- ) dup @ rot swap chain swap ! ; : :addrfilter ( w self -- ) CELLSZ + _chain! ; : :addwfilter ( w self -- ) CELLSZ << + _chain! ; - : :filters$ ( self -- ) - ['] _readbuf swap CELLSZ + !+ ['] _writebuf swap ! ; + : :filters$ ( self -- ) ['] readbuf swap CELLSZ + !+ ['] writebuf swap ! ; ]struct : _ioerr abort" Invalid I/O" ; @@ -426,7 +435,7 @@ struct+[ IO struct[ Filesystem sfield drv - sfield flags \ b0=writeable + sfield flags smethod :child smethod :info smethod :open @@ -436,12 +445,16 @@ struct[ Filesystem smethod :remove : :drv [compile] drv [compile] Drive ; immediate : :writeable? flags 1 and ; + : :new ( drv -- fs ) here swap ( drv ) , 0 ( flags ) , 7 nabort, ; + : :[methods] + '" child" , '" info" , '" open" , '" iter" , + '" newfile" , '" newdir" , '" remove" , ; ]struct \ bootfs holds a reference to boot FS. This is used until the full sys/file \ subsystem takes over with Path mechanics. -0 value bootfs \ has to be set before first use +0 value bootfs extends IO struct[ File - sfield pos \ offset from beginning of file + sfield pos sfield size sfield bufptr sfield bufsz @@ -450,6 +463,9 @@ extends IO struct[ File : :buf( bufptr ; : :)buf bi :buf( | bufsz + ; : :ptr bi+ pos | bufsz mod swap :buf( + ; + : :new ( -- hdl ) + IO :new 0 ( pos ) , 0 ( size ) , 0 ( bufptr ) , 0 ( bufsz ) , 2 nabort, ; + : :[methods] '" seek" , '" truncate" , ; ]struct \ File loading diff --git a/posix/glue.fs b/posix/glue.fs @@ -1,17 +1,15 @@ -: _ doer ' , does> nip @ execute ; -_ _:child _fchild _ _:open _fopen _ _:info _finfo _ _:iter _fiter - -create _POSIXFS - 0 , 0 , - ' _:child , - ' _:info , - ' _:open , - ' _:iter , - ' abort , - ' abort , - ' abort , - -_POSIXFS to bootfs +extends Filesystem struct[ POSIXFS + : _ doer ' , does> nip @ execute ; + _ child _fchild + _ open _fopen + _ info _finfo + _ iter _fiter + alias abort newfile + alias abort newdir + alias abort remove + : :new 0 Filesystem :new S[ :[methods] ]S c@+ -move, ; +]struct +POSIXFS :new to bootfs : mountImage ( imgname -- drv ) _mountdrv here 512 , -1 , ['] _drv@ , ['] _drv! , ;