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 @@
1implement Bufio;
2
3include "sys.m";
4 sys: Sys;
5
6include "bufio.m";
7
8UTFself: con 16r80; # ascii and UTF sequences are the same (<)
9Maxrune: con 8; # could probably be Sys->UTFmax
10Bufsize: con Sys->ATOMICIO;
11
12Filler: adt
13{
14 iobuf: ref Iobuf;
15 fill: BufioFill;
16 next: cyclic ref Filler;
17};
18
19fillers: ref Filler;
20
21create(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
30open(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
39fopen(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
48sopen(input: string): ref Iobuf
49{
50 return aopen(array of byte input);
51}
52
53aopen(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
60readchunk(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
89writechunk(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
115Iobuf.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
127Iobuf.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
147Iobuf.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
182Iobuf.offset(b: self ref Iobuf): big
183{
184 return b.bufpos + big b.index;
185}
186
187write2read(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
202Iobuf.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
230Iobuf.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
248Iobuf.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
256Iobuf.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
290Iobuf.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)
311tgets(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
342Iobuf.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
380Iobuf.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
394read2write(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
403Iobuf.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
430Iobuf.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
450Iobuf.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
471Iobuf.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
506filler(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
514Iobuf.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
522nofill(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 @@
1Bufio: 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
59BufioFill: module
60{
61 fill: fn(b: ref Bufio->Iobuf): int;
62};
63
64ChanFill: 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 @@
1implement String;
2
3include "string.m";
4
5splitl(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
15splitr(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
25drop(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
35take(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
45in(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
76splitstrl(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
95splitstrr(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
114prefix(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
124tolower(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
134toupper(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
144startnum(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
190tobig(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
214toint(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
238digit(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
250rpow(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
270match(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
284toreal(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
349append(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
366quoted(argv: list of string): string
367{
368 return quotedc(argv, nil);
369}
370
371quotedc(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
398unquoted(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 @@
1String: 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};