123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566openFmlibopenModule_typesmoduleBuffer:sigtypetvalmake:int->(Bytes.t->int->int->int)->(Bytes.t->int->int->int)->tvalis_ok:t->boolvalis_full:t->boolvalflush:t->unitmoduleRead:functor(W:WRITABLE)->sigendmoduleWrite:functor(R:READABLE)->sigvalwrite:t->R.t->R.tendend=structtypet={mutablerp:int;(* The content of the buffer is between the read and
the write pointer. *)mutablewp:int;mutableflag:bool;(* ok flag, set to false if (a) refilling a buffer
adds 0 bytes, (b) flushing a nonempty buffer
does not write anything to the filesystem. *)read:Bytes.t->int->int->int;(* refill function *)write:Bytes.t->int->int->int;(* flush function *)bytes:Bytes.t}letmake(n:int)(read:Bytes.t->int->int->int)(write:Bytes.t->int->int->int):t=assert(n>0);assert(n<=Sys.max_string_length);{rp=0;wp=0;bytes=Bytes.createn;flag=true;read;write}letis_ok(b:t):bool=b.flagletis_empty(b:t):bool=b.rp=b.wpletreset(b:t):unit=b.rp<-0;b.wp<-0letis_full(b:t):bool=b.wp=Bytes.lengthb.bytesletflush(b:t):unit=ifnot(is_emptyb)&&is_okbthenletn=b.writeb.bytesb.rp(b.wp-b.rp)inifn=0thenb.flag<-falseelse(* BUG: what if n > 0 && n <> b.wp - b.rp ?? Only a part of the
buffer has been written!! *)resetb(*let get (b:t): char =
assert (not (is_empty b));
let c = Bytes.get b.bytes b.rp in
b.rp <- b.rp + 1;
c*)letputc(b:t)(c:char):unit=assert(is_okb);ifis_fullbthenflushb;assert(not(is_fullb));Bytes.setb.bytesb.wpc;b.wp<-b.wp+1moduleRead(W:WRITABLE)=struct(*let read (b:t) (w:W.t): W.t =
let rec read w =
if not (is_empty b) && W.needs_more w then
read (W.putc w (get b))
else
w
in
read w*)endmoduleWrite(R:READABLE)=structletwrite(b:t)(r:R.t):R.t=letrecwriter=ifnot(is_fullb)&&R.has_morerthen(putcb(R.peekr);write(R.advancer))elserinwriterendend(* Buffer *)moduleFile_system:sigtypetvalmake:unit->tvalflush_all:t->unittypein_filetypeout_filevalstdin:in_filevalstdout:out_filevalstderr:out_file(*val getc: t -> in_file -> char option
val getline: t -> in_file -> string option
val putc: t -> out_file -> char -> unit
val open_for_read: t -> string -> in_file option
val open_for_write: t -> string -> out_file option
val create: t -> string -> out_file option
val close_in: t -> in_file -> unit
val close_out: t -> out_file -> unit*)valflush:t->out_file->unitmoduleRead:functor(W:WRITABLE)->sigvalread_buffer:t->in_file->W.t->W.tvalread:t->in_file->W.t->W.tendmoduleWrite:functor(R:READABLE)->sigvalwrite_buffer:t->out_file->R.t->R.tvalwrite:t->out_file->R.t->R.tendend=structtypefile=|ReadofUnix.file_descr*Buffer.t|WriteofUnix.file_descr*Buffer.t(*| Free of int*)typet={mutablefiles:filearray;mutablefirst_free:int;line_buf:Buffer.t}typein_file=inttypeout_file=intletbuffer_size=4096letunix_read(fd:Unix.file_descr)(b:Bytes.t)(ofs:int)(n:int):int=tryUnix.readfdbofsnwithUnix.Unix_error_->0letunix_write(fd:Unix.file_descr)(b:Bytes.t)(ofs:int)(n:int):int=tryUnix.writefdbofsnwithUnix.Unix_error_->0letreadable_file(fd:Unix.file_descr):file=Read(fd,Buffer.makebuffer_size(unix_readfd)(fun___->assertfalse))letwritable_file(fd:Unix.file_descr):file=Write(fd,Buffer.makebuffer_size(fun___->assertfalse)(unix_writefd))letmake():t={first_free=-1;files=[|readable_fileUnix.stdin;writable_fileUnix.stdout;writable_fileUnix.stderr|];line_buf=letfr___=assertfalseinletfw___=assertfalseinBuffer.make200frfw}(*let put_to_files (fs:t) (file:file): int option =
if fs.first_free >= 2 then
begin
let fd = fs.first_free in
match fs.files.(fd) with
| Free n ->
fs.first_free <- n;
fs.files.(fd) <- file;
Some fd
| _ ->
assert false (* Cannot happen, must be free! *)
end
else
begin
let nfiles = Array.length fs.files in
let files = Array.make (nfiles + 1) file in
Array.blit fs.files 0 files 0 nfiles;
fs.files <- files;
Some nfiles
end*)letwritable_buffer(fs:t)(fd:int):Buffer.t=assert(fd<Array.lengthfs.files);matchfs.files.(fd)with|Write(_,b)->b|_->assertfalse(*let readable_buffer (fs:t) (fd:int): Buffer.t =
assert (fd < Array.length fs.files);
match fs.files.(fd) with
| Read (_,b) ->
b
| _ ->
assert false*)(*let getc (fs:t) (fd:in_file): char option =
Buffer.getc (readable_buffer fs fd)
let putc (fs:t) (fd:out_file) (c:char): unit =
Buffer.putc (writable_buffer fs fd) c
let open_for_read (fs:t) (path:string): in_file option =
try
put_to_files
fs
(readable_file (Unix.openfile path [Unix.O_RDONLY] 0o640))
with Unix.Unix_error _ ->
None
let open_for_write (fs:t) (path:string): out_file option =
try
put_to_files
fs
(writable_file (Unix.openfile path [Unix.O_WRONLY] 0o640))
with Unix.Unix_error _ ->
None
let create (fs:t) (path:string): out_file option =
try
put_to_files
fs
(writable_file (Unix.openfile path [Unix.O_CREAT] 0o640))
with Unix.Unix_error _ ->
None*)(*let unix_file_descriptor (fs:t) (fd:int): Unix.file_descr =
assert (fd < Array.length fs.files);
match fs.files.(fd) with
| Read (fd,_) -> fd
| Write (fd,_) -> fd*)(*let close_file (fs:t) (fd:int): unit =
assert (fd < Array.length fs.files);
match fs.files.(fd) with
| Read (fd,_) ->
Unix.close fd
| Write (fd,b) ->
Buffer.flush b;
Unix.close fd
| Free _ ->
()
let close_in (fs:t) (fd:in_file): unit =
close_file fs fd
let close_out (fs:t) (fd:out_file): unit =
close_file fs fd*)letflush(fs:t)(fd:out_file):unit=assert(fd<Array.lengthfs.files);matchfs.files.(fd)with|Write(_,b)->Buffer.flushb|_->()letflush_all(fs:t):unit=fori=0toArray.lengthfs.files-1doflushfsidoneletstdin:in_file=0letstdout:out_file=1letstderr:out_file=2(*let stdin_buffer (fs:t): Buffer.t =
readable_buffer fs stdin
let stdout_buffer (fs:t): Buffer.t =
writable_buffer fs stdout
let stderr_buffer (fs:t): Buffer.t =
writable_buffer fs stderr
let getline (fs:t) (fd:in_file): string option =
assert (fd < Array.length fs.files);
let b = readable_buffer fs fd in
Buffer.reset fs.line_buf;
let content () = Some (Buffer.content fs.line_buf) in
let len = Buffer.size fs.line_buf
in
let rec read (i:int): string option =
if i = len then
content ()
else
begin
match Buffer.getc b with
| None ->
if i = 0 then
None
else
content ()
| Some c ->
if c = '\n' then
content ()
else
begin
Buffer.putc fs.line_buf c;
read (i+1)
end
end
in
read 0
*)moduleRead(W:WRITABLE)=structletread_buffer(_:t)(_:in_file)(_:W.t):W.t=assertfalseletread(_:t)(_:in_file)(_:W.t):W.t=assertfalseendmoduleWrite(R:READABLE)=structmoduleBW=Buffer.Write(R)letwrite_buffer(fs:t)(fd:out_file)(r:R.t):R.t=assert(fd<Array.lengthfs.files);BW.write(writable_bufferfsfd)rletwrite(fs:t)(fd:out_file)(r:R.t):R.t=assert(fd<Array.lengthfs.files);letb=writable_bufferfsfdinletrecwriter=letmore=R.has_morerinifnot(Buffer.is_fullb)&&morethenwrite@@BW.writebrelseifBuffer.is_okb&&morethen(Buffer.flushb;writer)elserinwriterendend(* File_system *)moduleIO0:Make_io.SIG=structtypeprogram=|Moreof(File_system.t*(File_system.t->program))|Doneletrecexecute_program:program->unit=function|Done->()|More(fs,f)->execute_program(ffs)(* [f fs] does one execution step and returns
the remainder of the program. *)(* The same as an iteration
========================
let execute_program (p:program): unit =
let pref = ref p in
while !pref <> Done do
match !pref with
| Done ->
assert false (* cannot happen *)
| More (fs, f) ->
pref := f fs
done
*)type'acont='a->File_system.t->programmoduleM=Monad.Of_sig_min(structtype'at=File_system.t->'acont->programletreturn(a:'a):'at=funfsk->kafslet(>>=)(m:'at)(f:'a->'bt):'bt=funfsk->mfs(funafs->More(fs,funfs->fafsk))end)includeMtypein_file=File_system.in_filetypeout_file=File_system.out_fileletstdin:in_file=File_system.stdinletstdout:out_file=File_system.stdoutletstderr:out_file=File_system.stderrletexit(code:int):'at=funfs_->File_system.flush_allfs;Stdlib.exitcodeletexecute(p:unitt):unit=letfs=File_system.make()inlet_=tryexecute_program(pfs(fun()_->Done))withe->File_system.flush_allfs;raiseeinFile_system.flush_allfs;Stdlib.exit0letcommand_line:stringarrayt=funfsk->kSys.argvfsletcurrent_working_directory:stringt=funfsk->k(Sys.getcwd())fsletpath_separator:char=ifSys.win32then'\\'else'/'letpath_delimiter:char=ifSys.win32then';'else':'letread_directory(path:string):stringarrayoptiont=funfsk->k(trySome(Sys.readdirpath)with_->None)fsletcli_prompt(prompt:string):stringoptiont=funfsk->File_system.flushfsstdout;k(letres=LNoise.linenoisepromptinmatchreswith|None->res|Somestr->ignore(LNoise.history_addstr);res)fsletcli_loop(state:'a)(get_prompt:'a->stringoption)(next:'a->string->'at)(stop:'a->'at):'at=letrecloopstate=matchget_promptstatewith|None->returnstate|Someprompt_string->cli_promptprompt_string>>=function|None->stopstate|Someline->nextstateline>>=loopinloopstatemoduleRead(W:WRITABLE)=structmoduleFS_Read=File_system.Read(W)letread_buffer(fd:in_file)(w:W.t):W.tt=funfsk->k(FS_Read.read_bufferfsfdw)fsletread(fd:in_file)(w:W.t):W.tt=funfsk->k(FS_Read.readfsfdw)fsendmoduleWrite(R:READABLE)=structmoduleFS_Write=File_system.Write(R)letwrite_buffer(fd:out_file)(r:R.t):R.tt=funfsk->k(FS_Write.write_bufferfsfdr)fsletwrite(fd:out_file)(r:R.t):R.tt=funfsk->k(FS_Write.writefsfdr)fsendendmoduleIO:Io.SIG=Make_io.Make(IO0)