History

Add dependent limbo libraries for the compiler.

arr committed 9 years ago

Commit 160df631 parent 99a0b814 files · +1071 −0Browse files

Unified · Split

4 files
  1. limbo/compiler/bufio.b +534 −0
  2. limbo/compiler/bufio.m +70 −0
  3. limbo/compiler/string.b +427 −0
  4. limbo/compiler/string.m +40 −0
limbo/compiler/bufio.b+534−0
@@ -0,0 +1,534 @@
1+implement Bufio;
2+
3+include "sys.m";
4+ sys: Sys;
5+
6+include "bufio.m";
7+
8+UTFself: con 16r80; # ascii and UTF sequences are the same (<)
9+Maxrune: con 8; # could probably be Sys->UTFmax
10+Bufsize: con Sys->ATOMICIO;
11+
12+Filler: adt
13+{
14+ iobuf: ref Iobuf;
15+ fill: BufioFill;
16+ next: cyclic ref Filler;
17+};
18+
19+fillers: ref Filler;
20+
21+create(filename: string, mode, perm: int): ref Iobuf
22+{
23+ if (sys == nil)
24+ sys = load Sys Sys->PATH;
25+ if ((fd := sys->create(filename, mode, perm)) == nil)
26+ return nil;
27+ return ref Iobuf(fd, array[Bufsize+Maxrune] of byte, 0, 0, 0, big 0, big 0, mode, mode);
28+}
29+
30+open(filename: string, mode: int): ref Iobuf
31+{
32+ if (sys == nil)
33+ sys = load Sys Sys->PATH;
34+ if ((fd := sys->open(filename, mode)) == nil)
35+ return nil;
36+ return ref Iobuf(fd, array[Bufsize+Maxrune] of byte, 0, 0, 0, big 0, big 0, mode, mode);
37+}
38+
39+fopen(fd: ref Sys->FD, mode: int): ref Iobuf
40+{
41+ if (sys == nil)
42+ sys = load Sys Sys->PATH;
43+ if ((filpos := sys->seek(fd, big 0, 1)) < big 0)
44+ filpos = big 0;
45+ return ref Iobuf(fd, array[Bufsize+Maxrune] of byte, 0, 0, 0, filpos, filpos, mode, mode);
46+}
47+
48+sopen(input: string): ref Iobuf
49+{
50+ return aopen(array of byte input);
51+}
52+
53+aopen(b: array of byte): ref Iobuf
54+{
55+ if (sys == nil)
56+ sys = load Sys Sys->PATH;
57+ return ref Iobuf(nil, b, 0, len b, 0, big 0, big 0, OREAD, OREAD);
58+}
59+
60+readchunk(b: ref Iobuf): int
61+{
62+ if (b.fd == nil){
63+ if ((f := filler(b)) != nil){
64+ if ((n := f.fill->fill(b)) == EOF)
65+ nofill(b);
66+ return n;
67+ }
68+ return EOF;
69+ }
70+ if (b.filpos != b.bufpos + big b.size) {
71+ s := b.bufpos + big b.size;
72+ if (sys->seek(b.fd, s, 0) != s)
73+ return ERROR;
74+ b.filpos = s;
75+ }
76+ i := len b.buffer - b.size - 1;
77+ if(i > Bufsize)
78+ i = Bufsize;
79+ if ((i = sys->read(b.fd, b.buffer[b.size:], i)) <= 0) {
80+ if(i < 0)
81+ return ERROR;
82+ return EOF;
83+ }
84+ b.size += i;
85+ b.filpos += big i;
86+ return i;
87+}
88+
89+writechunk(b: ref Iobuf): int
90+{
91+ err := (b.fd == nil);
92+ if (b.filpos != b.bufpos) {
93+ if (sys->seek(b.fd, b.bufpos, 0) != b.bufpos)
94+ err = 1;
95+ b.filpos = b.bufpos;
96+ }
97+ if ((size := b.size) > Bufsize)
98+ size = Bufsize;
99+ if (sys->write(b.fd, b.buffer, size) != size)
100+ err = 1;
101+ b.filpos += big size;
102+ b.size -= size;
103+ if (b.size) {
104+ b.dirty = 1;
105+ b.buffer[0:] = b.buffer[Bufsize:Bufsize+b.size];
106+ } else
107+ b.dirty = 0;
108+ b.bufpos += big size;
109+ b.index -= size;
110+ if(err)
111+ return ERROR;
112+ return size;
113+}
114+
115+Iobuf.close(b: self ref Iobuf)
116+{
117+ if (b.fd == nil) {
118+ nofill(b);
119+ return;
120+ }
121+ if (b.dirty)
122+ b.flush();
123+ b.fd = nil;
124+ b.buffer = nil;
125+}
126+
127+Iobuf.flush(b: self ref Iobuf): int
128+{
129+ if (b.fd == nil)
130+ return ERROR;
131+ if (b.lastop == OREAD){
132+ b.bufpos = b.filpos;
133+ b.size = 0;
134+ return 0;
135+ }
136+ while (b.dirty) {
137+ if (writechunk(b) < 0)
138+ return ERROR;
139+ if (b.index < 0) {
140+ b.bufpos += big b.index;
141+ b.index = 0;
142+ }
143+ }
144+ return 0;
145+}
146+
147+Iobuf.seek(b: self ref Iobuf, off: big, start: int): big
148+{
149+ npos: big;
150+
151+ if (b.fd == nil){
152+ if(filler(b) != nil)
153+ return big ERROR;
154+ }
155+ case (start) {
156+ 0 => # absolute address
157+ npos = off;
158+ 1 => # offset from current location
159+ npos = b.bufpos + big b.index + off;
160+ off = npos;
161+ start = Sys->SEEKSTART;
162+ 2 => # offset from EOF
163+ npos = big -1;
164+ * => return big ERROR;
165+ }
166+ if (b.bufpos <= npos && npos < b.bufpos + big b.size) {
167+ b.index = int(npos - b.bufpos);
168+ return npos;
169+ }
170+ if (b.fd == nil || b.dirty && b.flush() < 0)
171+ return big ERROR;
172+ b.size = 0;
173+ b.index = 0;
174+ if ((s := sys->seek(b.fd, off, start)) < big 0) {
175+ b.bufpos = b.filpos;
176+ return big ERROR;
177+ }
178+ b.bufpos = b.filpos = s;
179+ return s;
180+}
181+
182+Iobuf.offset(b: self ref Iobuf): big
183+{
184+ return b.bufpos + big b.index;
185+}
186+
187+write2read(b: ref Iobuf): int
188+{
189+ while (b.dirty)
190+ if (b.flush() < 0)
191+ return ERROR;
192+ b.bufpos = b.filpos;
193+ b.size = 0;
194+ b.lastop = OREAD;
195+ if ((r := readchunk(b)) < 0)
196+ return r;
197+ if (b.index > b.size)
198+ return EOF;
199+ return 0;
200+}
201+
202+Iobuf.read(b: self ref Iobuf, buf: array of byte, n: int): int
203+{
204+ if (b.mode == OWRITE)
205+ return ERROR;
206+ if (b.lastop != OREAD){
207+ if ((r := write2read(b)) < 0)
208+ return r;
209+ }
210+ k := n;
211+ while (b.size - b.index < k) {
212+ buf[0:] = b.buffer[b.index:b.size];
213+ buf = buf[b.size - b.index:];
214+ k -= b.size - b.index;
215+
216+ b.bufpos += big b.size;
217+ b.index = 0;
218+ b.size = 0;
219+ if ((r := readchunk(b)) < 0) {
220+ if(r == EOF || n != k)
221+ return n-k;
222+ return ERROR;
223+ }
224+ }
225+ buf[0:] = b.buffer[b.index:b.index+k];
226+ b.index += k;
227+ return n;
228+}
229+
230+Iobuf.getb(b: self ref Iobuf): int
231+{
232+ if(b.lastop != OREAD){
233+ if(b.mode == OWRITE)
234+ return ERROR;
235+ if((r := write2read(b)) < 0)
236+ return r;
237+ }
238+ if (b.index == b.size) {
239+ b.bufpos += big b.index;
240+ b.index = 0;
241+ b.size = 0;
242+ if ((r := readchunk(b)) < 0)
243+ return r;
244+ }
245+ return int b.buffer[b.index++];
246+}
247+
248+Iobuf.ungetb(b: self ref Iobuf): int
249+{
250+ if(b.mode == OWRITE || b.lastop != OREAD)
251+ return ERROR;
252+ b.index--;
253+ return 1;
254+}
255+
256+Iobuf.getc(b: self ref Iobuf): int
257+{
258+ r, i, s: int;
259+
260+ if(b.lastop != OREAD){
261+ if(b.mode == OWRITE)
262+ return ERROR;
263+ if((r = write2read(b)) < 0)
264+ return r;
265+ }
266+ for(;;) {
267+ if(b.index < b.size) {
268+ r = int b.buffer[b.index];
269+ if(r < UTFself){
270+ b.index++;
271+ return r;
272+ }
273+ (r, i, s) = sys->byte2char(b.buffer[0:b.size], b.index);
274+ if (i != 0) {
275+ b.index += i;
276+ return r;
277+ }
278+ b.buffer[0:] = b.buffer[b.index:b.size];
279+ }
280+ b.bufpos += big b.index;
281+ b.size -= b.index;
282+ b.index = 0;
283+ if ((r = readchunk(b)) < 0)
284+ return r;
285+ }
286+ # Not reached:
287+ return -1;
288+}
289+
290+Iobuf.ungetc(b: self ref Iobuf): int
291+{
292+ if(b.index == 0 || b.mode == OWRITE || b.lastop != OREAD)
293+ return ERROR;
294+ stop := b.index - Sys->UTFmax;
295+ if(stop < 0)
296+ stop = 0;
297+ buf := b.buffer[0:b.size];
298+ for(i := b.index-1; i >= stop; i--){
299+ (nil, n, s) := sys->byte2char(buf, i);
300+ if(s && i + n == b.index){
301+ b.index = i;
302+ return 1;
303+ }
304+ }
305+ b.index--;
306+
307+ return 1;
308+}
309+
310+# optimised when term < UTFself (common case)
311+tgets(b: ref Iobuf, t: int): string
312+{
313+ str: string;
314+ term := byte t;
315+ for(;;){
316+ start := b.index;
317+ end := start + sys->utfbytes(b.buffer[start:], b.size-start);
318+ buf := b.buffer;
319+ # XXX could speed up by adding extra byte to end of buffer and
320+ # placing a sentinel there (eliminate one test, perhaps 35% speedup).
321+ # (but not when we've been given the buffer externally)
322+ for(i := start; i < end; i++){
323+ if(buf[i] == term){
324+ i++;
325+ str += string buf[start:i];
326+ b.index = i;
327+ return str;
328+ }
329+ }
330+ str += string buf[start:i];
331+ if(i < b.size)
332+ b.buffer[0:] = buf[i:b.size];
333+ b.size -= i;
334+ b.bufpos += big i;
335+ b.index = 0;
336+ if(readchunk(b) < 0)
337+ break;
338+ }
339+ return str;
340+}
341+
342+Iobuf.gets(b: self ref Iobuf, term: int): string
343+{
344+ i: int;
345+
346+ if(b.mode == OWRITE)
347+ return nil;
348+ if(b.lastop != OREAD && write2read(b) < 0)
349+ return nil;
350+# if(term < UTFself)
351+# return tgets(b, term);
352+ str: string;
353+ ch := -1;
354+ for (;;) {
355+ start := b.index;
356+ n := 0;
357+ while(b.index < b.size){
358+ (ch, i, nil) = sys->byte2char(b.buffer[0:b.size], b.index);
359+ if(i == 0) # too few bytes for full Rune
360+ break;
361+ n += i;
362+ b.index += i;
363+ if(ch == term)
364+ break;
365+ }
366+ if(n > 0)
367+ str += string b.buffer[start:start+n];
368+ if(ch == term)
369+ return str;
370+ b.buffer[0:] = b.buffer[b.index:b.size];
371+ b.bufpos += big b.index;
372+ b.size -= b.index;
373+ b.index = 0;
374+ if (readchunk(b) < 0)
375+ break;
376+ }
377+ return str; # nil at EOF
378+}
379+
380+Iobuf.gett(b: self ref Iobuf, s: string): string
381+{
382+ r := "";
383+ if (b.mode == OWRITE || (ch := b.getc()) < 0)
384+ return nil;
385+ do {
386+ r[len r] = ch;
387+ for (i:=0; i<len(s); i++)
388+ if (ch == s[i])
389+ return r;
390+ } while ((ch = b.getc()) >= 0);
391+ return r;
392+}
393+
394+read2write(b: ref Iobuf)
395+{
396+ # last operation was a read
397+ b.bufpos += big b.index;
398+ b.size = 0;
399+ b.index = 0;
400+ b.lastop = OWRITE;
401+}
402+
403+Iobuf.write(b: self ref Iobuf, buf: array of byte, n: int): int
404+{
405+ if(b.lastop != OWRITE) {
406+ if(b.mode == OREAD)
407+ return ERROR;
408+ read2write(b);
409+ }
410+ start := 0;
411+ k := n;
412+ while(k > 0){
413+ nw := Bufsize - b.index;
414+ if(nw > k)
415+ nw = k;
416+ end := start + nw;
417+ b.buffer[b.index:] = buf[start:end];
418+ start = end;
419+ b.index += nw;
420+ k -= nw;
421+ if(b.index > b.size)
422+ b.size = b.index;
423+ b.dirty = 1;
424+ if(b.size == Bufsize && writechunk(b) < 0)
425+ return ERROR;
426+ }
427+ return n;
428+}
429+
430+Iobuf.putb(b: self ref Iobuf, c: byte): int
431+{
432+ if(b.lastop != OWRITE) {
433+ if(b.mode == OREAD)
434+ return ERROR;
435+ read2write(b);
436+ }
437+ b.buffer[b.index++] = c;
438+ if(b.index > b.size)
439+ b.size = b.index;
440+ b.dirty = 1;
441+ if(b.size >= Bufsize) {
442+ if (b.fd == nil)
443+ return ERROR;
444+ if (writechunk(b) < 0)
445+ return ERROR;
446+ }
447+ return 0;
448+}
449+
450+Iobuf.putc(b: self ref Iobuf, c: int): int
451+{
452+ if(b.lastop != OWRITE) {
453+ if (b.mode == OREAD)
454+ return ERROR;
455+ read2write(b);
456+ }
457+ if(c < UTFself)
458+ b.buffer[b.index++] = byte c;
459+ else
460+ b.index += sys->char2byte(c, b.buffer, b.index);
461+ if (b.index > b.size)
462+ b.size = b.index;
463+ b.dirty = 1;
464+ if (b.size >= Bufsize) {
465+ if (writechunk(b) < 0)
466+ return ERROR;
467+ }
468+ return 0;
469+}
470+
471+Iobuf.puts(b: self ref Iobuf, s: string): int
472+{
473+ if(b.lastop != OWRITE) {
474+ if (b.mode == OREAD)
475+ return ERROR;
476+ read2write(b);
477+ }
478+ n := len s;
479+ if (n == 0)
480+ return 0;
481+ ind := b.index;
482+ buf := b.buffer;
483+ for(i := 0; i < n; i++){
484+ c := s[i];
485+ if(c < UTFself)
486+ buf[ind++] = byte c;
487+ else
488+ ind += sys->char2byte(c, buf, ind);
489+ if(ind >= Bufsize){
490+ b.index = ind;
491+ if(ind > b.size)
492+ b.size = ind;
493+ b.dirty = 1;
494+ if(writechunk(b) < 0)
495+ return ERROR;
496+ ind = b.index;
497+ }
498+ }
499+ b.dirty = b.index != ind;
500+ b.index = ind;
501+ if (ind > b.size)
502+ b.size = ind;
503+ return n;
504+}
505+
506+filler(b: ref Iobuf): ref Filler
507+{
508+ for (f := fillers; f != nil; f = f.next)
509+ if(f.iobuf == b)
510+ return f;
511+ return nil;
512+}
513+
514+Iobuf.setfill(b: self ref Iobuf, fill: BufioFill)
515+{
516+ if ((f := filler(b)) != nil)
517+ f.fill = fill;
518+ else
519+ fillers = ref Filler(b, fill, fillers);
520+}
521+
522+nofill(b: ref Iobuf)
523+{
524+ prev: ref Filler;
525+ for(f := fillers; f != nil; f = f.next) {
526+ if(f.iobuf == b) {
527+ if (prev == nil)
528+ fillers = f.next;
529+ else
530+ prev.next = f.next;
531+ }
532+ prev = f;
533+ }
534+}
limbo/compiler/bufio.m+70−0
@@ -0,0 +1,70 @@
1+Bufio: module
2+{
3+ PATH: con "/dis/lib/bufio.dis";
4+
5+ SEEKSTART: con Sys->SEEKSTART;
6+ SEEKRELA: con Sys->SEEKRELA;
7+ SEEKEND: con Sys->SEEKEND;
8+
9+ OREAD: con Sys->OREAD;
10+ OWRITE: con Sys->OWRITE;
11+ ORDWR: con Sys->ORDWR;
12+
13+ EOF: con -1;
14+ ERROR: con -2;
15+
16+ Iobuf: adt {
17+ seek: fn(b: self ref Iobuf, n: big, where: int): big;
18+ offset: fn(b: self ref Iobuf): big;
19+
20+ read: fn(b: self ref Iobuf, a: array of byte, n: int): int;
21+ write: fn(b: self ref Iobuf, a: array of byte, n: int): int;
22+
23+ getb: fn(b: self ref Iobuf): int;
24+ getc: fn(b: self ref Iobuf): int;
25+ gets: fn(b: self ref Iobuf, sep: int): string;
26+ gett: fn(b: self ref Iobuf, sep: string): string;
27+
28+ ungetb: fn(b: self ref Iobuf): int;
29+ ungetc: fn(b: self ref Iobuf): int;
30+
31+ putb: fn(b: self ref Iobuf, b: byte): int;
32+ putc: fn(b: self ref Iobuf, c: int): int;
33+ puts: fn(b: self ref Iobuf, s: string): int;
34+
35+ flush: fn(b: self ref Iobuf): int;
36+ close: fn(b: self ref Iobuf);
37+
38+ setfill: fn(b: self ref Iobuf, f: BufioFill);
39+
40+ # Internal variables
41+ fd: ref Sys->FD; # the file
42+ buffer: array of byte; # the buffer
43+ index: int; # read/write pointer in buffer
44+ size: int; # characters remaining/written
45+ dirty: int; # needs flushing
46+ bufpos: big; # position in file of buf[0]
47+ filpos: big; # current file pointer
48+ lastop: int; # OREAD or OWRITE
49+ mode: int; # mode of open
50+ };
51+
52+ open: fn(name: string, mode: int): ref Iobuf;
53+ create: fn(name: string, mode, perm: int): ref Iobuf;
54+ fopen: fn(fd: ref Sys->FD, mode: int): ref Iobuf;
55+ sopen: fn(input: string): ref Iobuf;
56+ aopen: fn(input: array of byte): ref Iobuf;
57+};
58+
59+BufioFill: module
60+{
61+ fill: fn(b: ref Bufio->Iobuf): int;
62+};
63+
64+ChanFill: module
65+{
66+ PATH: con "/dis/lib/chanfill.dis";
67+
68+ init: fn(data: array of byte, fid: int, wc: Sys->Rwrite, r: ref Sys->FileIO, b: Bufio): ref Bufio->Iobuf;
69+ fill: fn(b: ref Bufio->Iobuf): int;
70+};
limbo/compiler/string.b+427−0
@@ -0,0 +1,427 @@
1+implement String;
2+
3+include "string.m";
4+
5+splitl(s: string, cl: string): (string, string)
6+{
7+ n := len s;
8+ for(j := 0; j < n; j++) {
9+ if(in(s[j], cl))
10+ return (s[0:j], s[j:n]);
11+ }
12+ return (s,"");
13+}
14+
15+splitr(s: string, cl: string): (string, string)
16+{
17+ n := len s;
18+ for(j := n-1; j >= 0; j--) {
19+ if(in(s[j], cl))
20+ return (s[0:j+1], s[j+1:n]);
21+ }
22+ return ("",s);
23+}
24+
25+drop(s: string, cl: string): string
26+{
27+ n := len s;
28+ for(j := 0; j < n; j++) {
29+ if(!in(s[j], cl))
30+ return (s[j:n]);
31+ }
32+ return "";
33+}
34+
35+take(s: string, cl: string): string
36+{
37+ n := len s;
38+ for(j := 0; j < n; j++) {
39+ if(!in(s[j], cl))
40+ return (s[0:j]);
41+ }
42+ return s;
43+}
44+
45+in(c: int, s: string): int
46+{
47+ n := len s;
48+ if(n == 0)
49+ return 0;
50+ ans := 0;
51+ negate := 0;
52+ if(s[0] == '^') {
53+ negate = 1;
54+ s = s[1:];
55+ n--;
56+ }
57+ for(i := 0; i < n; i++) {
58+ if(s[i] == '-' && i > 0 && i < n-1) {
59+ if(c >= s[i-1] && c <= s[i+1]) {
60+ ans = 1;
61+ break;
62+ }
63+ i++;
64+ }
65+ else
66+ if(c == s[i]) {
67+ ans = 1;
68+ break;
69+ }
70+ }
71+ if(negate)
72+ ans = !ans;
73+ return ans;
74+}
75+
76+splitstrl(s: string, t: string): (string, string)
77+{
78+ n := len s;
79+ nt := len t;
80+ if(nt == 0)
81+ return ("", s);
82+ c0 := t[0];
83+ mainloop:
84+ for(j := 0; j <= n-nt; j++) {
85+ if(s[j] == c0) {
86+ for(k := 1; k < nt; k++)
87+ if(s[j+k] != t[k])
88+ continue mainloop;
89+ return(s[0:j], s[j:n]);
90+ }
91+ }
92+ return (s,"");
93+}
94+
95+splitstrr(s: string, t: string): (string, string)
96+{
97+ n := len s;
98+ nt := len t;
99+ if(nt == 0)
100+ return (s, "");
101+ c0 := t[0];
102+ mainloop:
103+ for(j := n-nt; j >= 0; j--) {
104+ if(s[j] == c0) {
105+ for(k := 1; k < nt; k++)
106+ if(s[j+k] != t[k])
107+ continue mainloop;
108+ return(s[0:j+nt], s[j+nt:n]);
109+ }
110+ }
111+ return ("",s);
112+}
113+
114+prefix(pre: string, s: string): int
115+{
116+ if(len s < len pre)
117+ return 0;
118+ for(k := 0; k < len pre; k++)
119+ if(pre[k] != s[k])
120+ return 0;
121+ return 1;
122+}
123+
124+tolower(s: string): string
125+{
126+ for(i := 0; i < len s; i++) {
127+ c := s[i];
128+ if(c >= 'A' && c <= 'Z')
129+ s[i] += 'a' - 'A';
130+ }
131+ return s;
132+}
133+
134+toupper(s: string): string
135+{
136+ for(i := 0; i < len s; i++) {
137+ c := s[i];
138+ if(c >= 'a' && c <= 'z')
139+ s[i] += 'A' - 'a';
140+ }
141+ return s;
142+}
143+
144+startnum(s: string, base: int): (int, int, int)
145+{
146+ if(s == nil || base != 0 && (base < 2 || base > 36))
147+ return (0, 0, 0);
148+
149+ # skip possible leading white space
150+ c := ' ';
151+ for (i := 0; i < len s; i++) {
152+ c = s[i];
153+ if(c != ' ' && c != '\t' && c != '\n')
154+ break;
155+ }
156+
157+ # optional sign
158+ neg := 0;
159+ if(c == '-' || c == '+') {
160+ if(c == '-')
161+ neg = 1;
162+ i++;
163+ }
164+
165+ if(base == 0) {
166+ # parse possible leading base designator
167+ start := i;
168+ base = -1;
169+ for (; i < start+3 && i < len s; i++) {
170+ c = s[i];
171+ if (c == 'r' && i > start) {
172+ base = int s[start:i];
173+ i++;
174+ break;
175+ } else if (c < '0' || c > '9')
176+ break;
177+ }
178+ if (base == -1) {
179+ i = start;
180+ base = 10;
181+ } else if (base == 0 || base > 36)
182+ return (0, 0, i);
183+ }
184+ if(i >= len s)
185+ return (0, 0, 0);
186+
187+ return (base, neg, i);
188+}
189+
190+tobig(s: string, base: int): (big, string)
191+{
192+ neg, i: int;
193+
194+ (base, neg, i) = startnum(s, base);
195+ if(base == 0)
196+ return (big 0, s);
197+
198+ # parse number itself.
199+ # probably this should check for overflow, and max out, as limbo op does?
200+ start := i;
201+ n := big 0;
202+ for (; i < len s; i++) {
203+ if((d := digit(s[i], base)) < 0)
204+ break;
205+ n = n*big base + big d;
206+ }
207+ if (i == start)
208+ return (big 0, s);
209+ if (neg)
210+ return (-n, s[i:]);
211+ return (n, s[i:]);
212+}
213+
214+toint(s: string, base: int): (int, string)
215+{
216+ neg, i: int;
217+
218+ (base, neg, i) = startnum(s, base);
219+ if(base == 0)
220+ return (0, s);
221+
222+ # parse number itself.
223+ # probably this should check for overflow, and max out, as limbo op does?
224+ start := i;
225+ n := 0;
226+ for (; i < len s; i++){
227+ if((d := digit(s[i], base)) < 0)
228+ break;
229+ n = n*base + d;
230+ }
231+ if (i == start)
232+ return (0, s);
233+ if (neg)
234+ return (-n, s[i:]);
235+ return (n, s[i:]);
236+}
237+
238+digit(c: int, base: int): int
239+{
240+ if ('0' <= c && c <= '0' + base - 1)
241+ return c-'0';
242+ else if ('a' <= c && c < 'a' + base - 10)
243+ return (c - 'a' + 10);
244+ else if ('A' <= c && c < 'A' + base - 10)
245+ return (c - 'A' + 10);
246+ else
247+ return -1;
248+}
249+
250+rpow(x: real, n: int): real
251+{
252+ inv := 0;
253+ if(n < 0){
254+ n = -n;
255+ inv = 1;
256+ }
257+ r := 1.0;
258+ for(;;){
259+ if(n&1)
260+ r *= x;
261+ if((n >>= 1) == 0)
262+ break;
263+ x *= x;
264+ }
265+ if(inv)
266+ r = 1.0/r;
267+ return r;
268+}
269+
270+match(p: string, s: string, i: int): int
271+{
272+ if(i+len p > len s)
273+ return 0;
274+ for(j := 0; j < len p; j++){
275+ c := s[i++];
276+ if(c >= 'A' && c <= 'Z')
277+ c += 'a'-'A';
278+ if(p[j] != c)
279+ return 0;
280+ }
281+ return 1;
282+}
283+
284+toreal(s: string, base: int): (real, string)
285+{
286+ neg, i: int;
287+
288+ (base, neg, i) = startnum(s, base);
289+ if(base == 0)
290+ return (0.0, s);
291+
292+ c := s[i];
293+ if((c == 'i' || c == 'I') && match("infinity", s, i))
294+ return (real s, s[i+8:]);
295+ if((c == 'n' || c == 'N') && match("nan", s, i))
296+ return (real s, s[i+3:]);
297+
298+ if(digit(c, base) < 0)
299+ return (0.0, s);
300+
301+ num := 0.0;
302+ for(; i < len s && (d := digit(s[i], base)) >= 0; i++)
303+ num = num*real base + real d;
304+ dig := 0; # digits in fraction
305+ if(i < len s && s[i] == '.'){
306+ i++;
307+ for(; i < len s && (d = digit(s[i], base)) >= 0; i++){
308+ num = num*real base + real d;
309+ dig++;
310+ }
311+ }
312+ exp := 0;
313+ eneg := 0;
314+ if(i < len s && ((c = s[i]) == 'e' || c == 'E')){
315+ start := i; # might still be badly formed
316+ i++;
317+ if(i < len s && ((c = s[i]) == '-' || c == '+')){
318+ i++;
319+ if(c == '-'){
320+ dig = -dig;
321+ eneg = 1;
322+ }
323+ }
324+ if(i < len s && s[i] >= '0' && s[i] <= '9'){ # exponents are always decimal
325+ for(; i < len s && (d = digit(s[i], 10)) >= 0; i++)
326+ exp = exp*base + d;
327+ }else
328+ i = start;
329+ }
330+ if(base == 10)
331+ return (real s[0: i], s[i:]); # conversion can be more accurate
332+ exp -= dig;
333+ if(exp < 0){
334+ exp = -exp;
335+ eneg = !eneg;
336+ }
337+ if(exp < 0 || exp > 19999)
338+ exp = 19999; # huge but otherwise arbitrary limit
339+ dem := rpow(real base, exp);
340+ if(eneg)
341+ num /= dem;
342+ else
343+ num *= dem;
344+ if(neg)
345+ return (-num,s[i:]);
346+ return (num, s[i:]);
347+}
348+
349+append(s: string, l: list of string): list of string
350+{
351+ t: list of string;
352+
353+ # Reverse l, prepend s, and reverse result.
354+ while (l != nil) {
355+ t = hd l :: t;
356+ l = tl l;
357+ }
358+ t = s :: t;
359+ do {
360+ l = hd t :: l;
361+ t = tl t;
362+ } while (t != nil);
363+ return l;
364+}
365+
366+quoted(argv: list of string): string
367+{
368+ return quotedc(argv, nil);
369+}
370+
371+quotedc(argv: list of string, cl: string): string
372+{
373+ s := "";
374+ while(argv != nil){
375+ arg := hd argv;
376+ for(i := 0; i < len arg; i++){
377+ c := arg[i];
378+ if(c == ' ' || c == '\t' || c == '\n' || c == '\'' || in(c, cl))
379+ break;
380+ }
381+ if(i < len arg || arg == nil){
382+ s += "'" + arg[0:i];
383+ for(; i < len arg; i++){
384+ if (arg[i] == '\'')
385+ s[len s] = '\'';
386+ s[len s] = arg[i];
387+ }
388+ s[len s] = '\'';
389+ }else
390+ s += arg;
391+ if(tl argv != nil)
392+ s[len s] = ' ';
393+ argv = tl argv;
394+ }
395+ return s;
396+}
397+
398+unquoted(s: string): list of string
399+{
400+ args: list of string;
401+ word: string;
402+ inquote := 0;
403+ for(j := len s; j > 0;){
404+ c := s[j-1];
405+ if(c == ' ' || c == '\t' || c == '\n'){
406+ j--;
407+ continue;
408+ }
409+ for(i := j-1; i >= 0 && ((c = s[i]) != ' ' && c != '\t' && c != '\n' || inquote); i--){ # collect word
410+ if(c == '\''){
411+ word = s[i+1:j] + word;
412+ j = i;
413+ if(!inquote || i == 0 || s[i-1] != '\'')
414+ inquote = !inquote;
415+ else
416+ i--;
417+ }
418+ }
419+ args = (s[i+1:j]+word) :: args;
420+ word = nil;
421+ j = i;
422+ }
423+ # if quotes were unbalanced, balance them and try again.
424+ if(inquote)
425+ return unquoted(s + "'");
426+ return args;
427+}
limbo/compiler/string.m+40−0
@@ -0,0 +1,40 @@
1+String: module
2+{
3+ PATH: con "/dis/lib/string.dis";
4+
5+ # the second arg of the following is a character class
6+ # e.g., "a-zA-Z", or "^ \t\n"
7+ # (ranges indicated by - except in first position;
8+ # ^ is first position means "not in" the following class)
9+ # splitl splits just before first char in class; (s, "") if no split
10+ # splitr splits just after last char in class; ("", s) if no split
11+ # drop removes maximal prefix in class
12+ # take returns maximal prefix in class
13+
14+ splitl: fn(s, cl: string): (string, string);
15+ splitr: fn(s, cl: string): (string, string);
16+ drop: fn(s, cl: string): string;
17+ take: fn(s, cl: string): string;
18+ in: fn(c: int, cl: string): int;
19+
20+ # in these, the second string is a string to match, not a class
21+ splitstrl: fn(s, t: string): (string, string);
22+ splitstrr: fn(s, t: string): (string, string);
23+
24+ # is first arg a prefix of second?
25+ prefix: fn(pre, s: string): int;
26+
27+ tolower: fn(s: string): string;
28+ toupper: fn(s: string): string;
29+
30+ # string to int returning value, remainder
31+ toint: fn(s: string, base: int): (int, string);
32+ tobig: fn(s: string, base: int): (big, string);
33+ toreal: fn(s: string, base: int): (real, string);
34+
35+ # append s to end of l
36+ append: fn(s: string, l: list of string): list of string;
37+ quoted: fn(argv: list of string): string;
38+ quotedc: fn(argv: list of string, cl: string): string;
39+ unquoted: fn(args: string): list of string;
40+};