``If, reader, you are slow now to believe What I shall tell, that is no cause for wonder, For I who saw it hardly can accept it.'' Dante Alighieri, Inferno, Canto XXV.
byte | unsigned, 8 bits |
int | signed, 32 bits |
big | signed, 64 bits |
real | IEEE long float, 64 bits |
nl := byte 10;
if (expr) stat if (expr) stat else stat while (expr) stat for (expr; expr; expr) stat do stat while (expr) ; return expr ; exit ;
implement Hello; include "sys.m"; sys: Sys; include "draw.m"; Hello: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; init(ctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; sys->print("hello, world\n"); }
$ limbo -g hello.b
$ limbo -g hello.b $ emu Inferno main (pid=6559) interp Initialize Dis: /dis/sh.dis slocum.cs.bell-labs.com$ /usr/bwk/hello hello, world slocum.cs.bell-labs.com$
implement Hello2; include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; include "tk.m"; tk: Tk; Hello2: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; init(ctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; draw = load Draw Draw->PATH; tk = load Tk Tk->PATH; t := tk->toplevel(ctxt.screen, ""); tk->cmd(t, "button .b -text {hello, world}"); tk->cmd(t, "pack .b"); tk->cmd(t, "update"); sys->sleep(10000); # wait 10 seconds }
... t := tk->toplevel(ctxt.screen, ""); cmd := chan of string; tk->namechan(t, cmd, "cmd"); # associate Limbo channel with Tk string tk->cmd(t, "button .b -text {Delete me} -command {send cmd bye}"); tk->cmd(t, "pack .b"); tk->cmd(t, "update"); <- cmd; # wait for something to arrive on channel }
# declarations omitted... init(ctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; argv = tl argv; # skip over program name for (s := ""; argv != nil; argv = tl argv) s += " " + hd argv; if (s != "") # something was stored in s sys->print("%s\n", s[1:]); }
s := ""
# declarations omitted... init(nil: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; buf := array[1] of byte; stdin := sys->fildes(0); OUT: con 0; IN: con 1; state := OUT; nl := 0; nw := 0; nc := 0; for (;;) { n := sys->read(stdin, buf, 1); if (n <= 0) break; c := int buf[0]; nc++; if (c == '\n') nl++; if (c == ' ' || c == '\t' || c == '\n') state = OUT; else if (state == OUT) { state = IN; nw++; } } sys->print("%d %d %d\n", nl, nw, nc); }
nl := 0; nw := 0; nc := 0;
stdin := sys->fildes(0);
OUT: con 0; IN: con 1;
state := OUT;
buf := array[1] of byte;
buf : array of byte; # no size at declaration buf = array[1] of byte; # size needed at creation
c := int buf[0];
# declarations omitted... include "bufio.m"; bufmod: Bufio; Iobuf: import bufmod; iob: ref Iobuf; init(nil: ref Draw->Context, nil: list of string) { sys = load Sys Sys->PATH; bufmod = load Bufio Bufio->PATH; if (bufmod == nil) { sys->print("bufmod load: %r\n"); exit; } stdin := sys->fildes(0); iob = bufmod->fopen(stdin, bufmod->OREAD); if (iob == nil) { sys->print("iob open: %r\n"); exit; } OUT: con 0; IN: con 1; state := OUT; nl := 0; nw := 0; nc := 0; for (;;) { c := iob.getc(); if (c == bufmod->EOF) break; nc++; if (c == '\n') nl++; if (c == ' ' || c == '\t' || c == '\n') state = OUT; else if (state == OUT) { state = IN; nw++; } } sys->print("%d %d %d\n", nl, nw, nc); }
include "bufio.m"; bufmod: Bufio;
Bufio: module # edited to fit your screen { PATH: con "/dis/bufio.dis"; EOF: con -1; Iobuf: adt { fd: ref Sys->FD; # the file buffer: array of byte; # the buffer # other variables omitted getc: fn(b: self ref Iobuf) : int; gets: fn(b: self ref Iobuf, sep: int) : string; close: fn(b: self ref Iobuf); }; open: fn(name: string, mode: int) : ref Iobuf; fopen: fn(fd: ref Sys->FD, mode: int) : ref Iobuf; };
Modulename->name
modulehandle->functionname modulehandle->variablename modulehandle->adtname.membername
iob: ref bufmod->Iobuf; bufmod->open(...) bufmod->iob.getc() bufmod->iob.fd
Iobuf: import bufmod;
adtvar := adtname(list of values for all members, in order); adtvar := ref adtname(list of values for all members, in order);
Hashtab: module { PATH: con "/usr/bwk/hashtab.dis"; # temporary name Table: adt { tab: array of list of (string, string); alloc: fn(n: int) : ref Table; hash: fn(ht: self ref Table, name: string) : int; add: fn(ht: self ref Table, name: string, val: string); lookup: fn(ht: self ref Table, name: string) : (int, string); }; };
implement Hashtab; include "hashtab.m"; Table.alloc(n: int) : ref Table { return ref Table(array[n] of list of (string,string)); } Table.hash(ht: self ref Table, s: string) : int { h := 0; for (i := 0; i < len s; i++) h = (h << 1) ^ int s[i]; h %= len ht.tab; if (h < 0) h += len ht.tab; return h; } Table.add(ht: self ref Table, name: string, val: string) { h := ht.hash(name); for (p := ht.tab[h]; p != nil; p = tl p) { (tname, nil) := hd p; if (tname == name) { # illegal: hd p = (tname, val); return; } } ht.tab[h] = (name, val) :: ht.tab[h]; } Table.lookup(ht: self ref Table, name: string) : (int, string) { h := ht.hash(name); for (p := ht.tab[h]; p != nil; p = tl p) { (tname, tval) := hd p; if (tname == name) return (1, tval); } return (0, ""); }
(tname, tval) := hd p;
ht.tab[h] = (name, val) :: ht.tab[h];
(tname, nil) := hd p;
# illegal: hd p = (tname, val);
nvtab = Table.alloc(101); # make a Table nvtab.add("Rob", "Pike"); nvtab.add("Howard", "Trickey"); (p, phil) := nvtab.lookup("Phil"); (q, sean) := nvtab.lookup("Sean");
Awk: module { PATH: con "/usr/bwk/awk.dis"; init: fn(argv: list of string); getline: fn() : array of string; NR: fn() : int; NF: fn() : int; FILENAME: fn() : string; };
implement Awk; include "sys.m"; sys: Sys; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; iobuf: ref Iobuf; include "awk.m"; _NR: int; _NF: int; _FILENAME: string; argv: list of string; init(av: list of string) { argv = tl av; if (len argv == 0) # no args => stdin argv = "-" :: nil; sys = load Sys Sys->PATH; bufio = load Bufio Bufio->PATH; } getline() : array of string { t := array[100] of string; fl : list of string; top: while (argv != nil) { if (_FILENAME == nil) { # advance to next file _FILENAME = hd argv; if (_FILENAME == "-") iobuf = bufio->fopen(sys->fildes(0), bufio->OREAD); else iobuf = bufio->open(_FILENAME, bufio->OREAD); if (iobuf == nil) { sys->print("getline %s: %r\n", _FILENAME); argv = nil; return nil; } } s := iobuf.gets('\n'); if (s == nil) { iobuf.close(); _FILENAME = nil; argv = tl argv; continue top; } t[0] = s[0:len s - 1]; _NR++; (_NF, fl) = sys->tokenize(t[0], " \t\n\r"); for (i := 1; fl != nil; fl = tl fl) t[i++] = hd fl; return t[0:i]; } return nil; } NR() : int { return _NR; } NF() : int { return _NF; } FILENAME() : string { return _FILENAME; }
(_NF, fl) = sys->tokenize(t[0], " \t\n\r");
implement Fmt; include "sys.m"; sys: Sys; include "draw.m"; Fmt: module { init: fn(nil: ref Draw->Context, argv: list of string); }; include "awk.m"; awk: Awk; getline, NF: import awk; out: array of string; nout: int; length: int; linelen := 65; init(nil: ref Draw->Context, argv: list of string) { t: array of string; out = array[100] of string; sys = load Sys Sys->PATH; awk = load Awk Awk->PATH; if (awk == nil) { sys->print("load awk: %r\n"); return; } awk->init(argv); nout = 0; length = 0; while ((t = getline()) != nil) { nf := NF(); if (nf == 0) { printline(); sys->print("\n"); } else for (i := 1; i <= nf; i++) { if (length + len t[i] > linelen) printline(); out[nout++] = t[i]; length += len t[i] + 1; } } printline(); } printline() { if (nout == 0) return; for (i := 0; i < nout-1; i++) sys->print("%s ", out[i]); sys->print("%s\n", out[i]); nout = 0; length = 0; }
# declarations omitted... WORD, BREAK, EOF : con iota; wds: chan of (int, string); init(nil: ref Draw->Context, nil: list of string) { sys = load Sys Sys->PATH; bufmod = load Bufio Bufio->PATH; stdin := sys->fildes(0); iob = bufmod->fopen(stdin, bufmod->OREAD); wds = chan of (int, string); spawn getword(wds); putword(wds); } getword(wds: chan of (int, string)) { while ((s := iob.gets('\n')) != nil) { (n, fl) := sys->tokenize(s, " \t\n"); if (n == 0) wds <-= (BREAK, ""); else for ( ; fl != nil; fl = tl fl) wds <-= (WORD, hd fl); } wds <-= (EOF, ""); } putword(wds: chan of (int, string)) { wd: int; s: string; for (length := 0;;) { (wd, s) =<- wds; case wd { BREAK => sys->print("\n\n"); length = 0; WORD => if (length + len s > 65) { sys->print("\n"); length = 0; } sys->print("%s ", s); length += len s + 1; EOF => sys->print("\n"); exit; } } }
'a' to 'z' or 'A' to 'Z' =>
tk->cmd("button .b -text {Push me} -command {send cmd .bpush}");
implement Etch; include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; include "tk.m"; tk: Tk; Etch: module { init: fn(ctxt: ref Draw->Context, argv: list of string); }; init(ctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; draw = load Draw Draw->PATH; tk = load Tk Tk->PATH; x, y, lastx, lasty: int; t := tk->toplevel(ctxt.screen, ""); cmd := chan of string; tk->namechan(t, cmd, "cmd"); tk->cmd(t, "canvas .c -height 400 -width 600 -background white"); tk->cmd(t, "frame .f"); tk->cmd(t, "button .f.c -text {Clear} -command {send cmd clear}"); tk->cmd(t, "button .f.d -text {Done} -command {send cmd quit}"); tk->cmd(t, "pack .f.c .f.d -side left -fill x -expand 1"); tk->cmd(t, "pack .c .f -side top -fill x"); tk->cmd(t, "bind .c <ButtonPress-1> {send cmd b1down %x %y}"); tk->cmd(t, "bind .c <Button-1-Motion> {send cmd b1motion %x %y}"); tk->cmd(t, "update"); for (;;) { s := <-cmd; (n, cmdstr) := sys->tokenize(s, " \t\n"); case hd cmdstr { "quit" => exit; "clear" => tk->cmd(t, ".c delete all; update"); "b1down" => lastx = int hd tl cmdstr; lasty = int hd tl tl cmdstr; cstr := sys->sprint(".c create line %d %d %d %d -width 2", lastx, lasty, lastx, lasty); tk->cmd(t, cstr); "b1motion" => x = int hd tl cmdstr; y = int hd tl tl cmdstr; cstr := sys->sprint(".c create line %d %d %d %d -width 2", lastx, lasty, x, y); tk->cmd(t, cstr); lastx = x; lasty = y; } tk->cmd(t, "update"); } }
s := <-cmd
init(ctxt: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; draw = load Draw Draw->PATH; tk = load Tk Tk->PATH; wmlib = load Wmlib Wmlib->PATH; wmlib->init(); tkargs := ""; argv = tl argv; # remove program name if (argv != nil) { # and extract any -geom arg tkargs = hd argv; argv = tl argv; } (t, menubut) := wmlib->titlebar(ctxt.screen, tkargs, "Othello", Wmlib->Appl); cmd := chan of string; tk->namechan(t, cmd, "cmd"); tk->cmd(t, "canvas .c -height 400 -width 400 -background green"); tk->cmd(t, "frame .f"); tk->cmd(t, "label .f.l -text {Othello?} -background white"); tk->cmd(t, "button .f.c -text {Reset} -command {send cmd Reset}"); tk->cmd(t, "button .f.d -text {Quit} -command {send cmd Quit}"); tk->cmd(t, "pack .f.l .f.c .f.d -side left -fill x -expand 1"); tk->cmd(t, "pack .Wm_t .c .f -side top -fill x"); tk->cmd(t, "bind .c <ButtonRelease-1> {send cmd B1up %x %y}"); for (i := 1; i < 9; i++) for (j := 1; j < 9; j++) { coord := sys->sprint("%d %d %d %d", SQ*i, SQ*j, SQ*(i+1), SQ*(j+1)); tk->cmd(t, ".c create rectangle " + coord + " -outline black -width 2"); } tk->cmd(t, "update"); lasterror(t, "init"); board = array[10] of {* => array[10] of int}; score = array[10] of {* => array[10] of int}; reinit(); for (;;) { alt { s := <- cmd => (n, l) := sys->tokenize(s, " \t"); case hd l { "Quit" => exit; "Reset" => reinit(); "B1up" => x := int hd tl l; y := int hd tl tl l; mouseUp(int x, int y); } menu := <-menubut => wmlib->titlectl(t, menu); } } }
lasterror(t: ref Tk->Toplevel, where: string) { s := tk->cmd(t, "variable lasterror"); if (s != nil) sys->print("%s: tk error %s\n", where, s); }