|
221 | 221 |
|
222 | 222 | (define (newline? c) (eqv? c #\newline)) |
223 | 223 |
|
224 | | -(define (skip-to-eol port) |
225 | | - (let ((c (peek-char port))) |
226 | | - (cond ((eof-object? c) c) |
227 | | - ((eqv? c #\newline) c) |
228 | | - (else (read-char port) |
229 | | - (skip-to-eol port))))) |
230 | | - |
231 | 224 | (define (op-or-sufchar? c) (or (op-suffix-char? c) (opchar? c))) |
232 | 225 |
|
233 | 226 | (define (read-operator port c0 (postfix? #f)) |
|
495 | 488 | (pair? (cadr t)) (eq? (car (cadr t)) 'core) |
496 | 489 | (memq (cadadr t) '(@int128_str @uint128_str @big_str)))) |
497 | 490 |
|
| 491 | +(define (make-bidi-state) '(0 . 0)) |
| 492 | + |
| 493 | +(define (update-bidi-state st c) |
| 494 | + (case c |
| 495 | + ((#\U202A #\U202B #\U202D #\U202E) (cons (+ (car st) 1) (cdr st))) ;; LRE RLE LRO RLO |
| 496 | + ((#\U2066 #\U2067 #\U2068) (cons (car st) (+ (cdr st) 1))) ;; LRI RLI FSI |
| 497 | + ((#\U202C) (cons (- (car st) 1) (cdr st))) ;; PDF |
| 498 | + ((#\U2069) (cons (car st) (- (cdr st) 1))) ;; PDI |
| 499 | + ((#\newline) '(0 . 0)) |
| 500 | + (else st))) |
| 501 | + |
| 502 | +(define (bidi-state-terminated? st) (equal? st '(0 . 0))) |
| 503 | + |
| 504 | +(define (skip-line-comment port) |
| 505 | + (let ((c (peek-char port))) |
| 506 | + (cond ((eof-object? c) c) |
| 507 | + ((eqv? c #\newline) c) |
| 508 | + (else (read-char port) |
| 509 | + (skip-line-comment port))))) |
| 510 | + |
| 511 | +(define (skip-multiline-comment port count bds) |
| 512 | + (let ((c (read-char port))) |
| 513 | + (if (eof-object? c) |
| 514 | + (error "incomplete: unterminated multi-line comment #= ... =#") ; NOTE: changing this may affect code in base/client.jl |
| 515 | + (if (eqv? c #\=) |
| 516 | + (let ((c (peek-char port))) |
| 517 | + (if (eqv? c #\#) |
| 518 | + (begin |
| 519 | + (read-char port) |
| 520 | + (if (> count 1) |
| 521 | + (skip-multiline-comment port (- count 1) bds) |
| 522 | + (if (not (bidi-state-terminated? bds)) |
| 523 | + (error "unbalanced bidirectional formatting in comment")))) |
| 524 | + (skip-multiline-comment port count (update-bidi-state bds c)))) |
| 525 | + (if (eqv? c #\#) |
| 526 | + (skip-multiline-comment port |
| 527 | + (if (eqv? (peek-char port) #\=) |
| 528 | + (begin (read-char port) |
| 529 | + (+ count 1)) |
| 530 | + count) |
| 531 | + bds) |
| 532 | + (skip-multiline-comment port count (update-bidi-state bds c))))))) |
| 533 | + |
498 | 534 | ;; skip to end of comment, starting at #: either #...<eol> or #= .... =#. |
499 | 535 | (define (skip-comment port) |
500 | | - (define (skip-multiline-comment port count) |
501 | | - (let ((c (read-char port))) |
502 | | - (if (eof-object? c) |
503 | | - (error "incomplete: unterminated multi-line comment #= ... =#") ; NOTE: changing this may affect code in base/client.jl |
504 | | - (begin (if (eqv? c #\=) |
505 | | - (let ((c (peek-char port))) |
506 | | - (if (eqv? c #\#) |
507 | | - (begin |
508 | | - (read-char port) |
509 | | - (if (> count 1) |
510 | | - (skip-multiline-comment port (- count 1)))) |
511 | | - (skip-multiline-comment port count))) |
512 | | - (if (eqv? c #\#) |
513 | | - (skip-multiline-comment port |
514 | | - (if (eqv? (peek-char port) #\=) |
515 | | - (begin (read-char port) |
516 | | - (+ count 1)) |
517 | | - count)) |
518 | | - (skip-multiline-comment port count))))))) |
519 | | - |
520 | 536 | (read-char port) ; read # that was already peeked |
521 | 537 | (if (eqv? (peek-char port) #\=) |
522 | 538 | (begin (read-char port) ; read initial = |
523 | | - (skip-multiline-comment port 1)) |
524 | | - (skip-to-eol port))) |
| 539 | + (skip-multiline-comment port 1 (make-bidi-state))) |
| 540 | + (skip-line-comment port))) |
525 | 541 |
|
526 | 542 | (define (skip-ws-and-comments port) |
527 | 543 | (skip-ws port #t) |
|
2336 | 2352 | (let loop ((c (read-char p)) |
2337 | 2353 | (b (open-output-string)) |
2338 | 2354 | (e ()) |
2339 | | - (quotes 0)) |
| 2355 | + (quotes 0) |
| 2356 | + (bds (make-bidi-state))) |
2340 | 2357 | (cond |
2341 | 2358 | ((eqv? c delim) |
2342 | 2359 | (if (< quotes n) |
2343 | | - (loop (read-char p) b e (+ quotes 1)) |
2344 | | - (reverse (cons (io.tostring! b) e)))) |
| 2360 | + (loop (read-char p) b e (+ quotes 1) bds) |
| 2361 | + (begin |
| 2362 | + (if (not (bidi-state-terminated? bds)) |
| 2363 | + (error "unbalanced bidirectional formatting in string literal")) |
| 2364 | + (reverse (cons (io.tostring! b) e))))) |
2345 | 2365 |
|
2346 | 2366 | ((= quotes 1) |
2347 | 2367 | (if (not raw) (write-char #\\ b)) |
2348 | 2368 | (write-char delim b) |
2349 | | - (loop c b e 0)) |
| 2369 | + (loop c b e 0 (update-bidi-state bds c))) |
2350 | 2370 |
|
2351 | 2371 | ((= quotes 2) |
2352 | 2372 | (if (not raw) (write-char #\\ b)) |
2353 | 2373 | (write-char delim b) |
2354 | 2374 | (if (not raw) (write-char #\\ b)) |
2355 | 2375 | (write-char delim b) |
2356 | | - (loop c b e 0)) |
| 2376 | + (loop c b e 0 (update-bidi-state bds c))) |
2357 | 2377 |
|
2358 | 2378 | ((eqv? c #\\) |
2359 | 2379 | (if raw |
|
2366 | 2386 | (io.write b (string.rep "\\" (div count 2))) |
2367 | 2387 | (if (odd? count) |
2368 | 2388 | (begin (write-char delim b) |
2369 | | - (loop (read-char p) b e 0)) |
2370 | | - (loop nxch b e 0))) |
| 2389 | + (loop (read-char p) b e 0 bds)) |
| 2390 | + (loop nxch b e 0 bds))) |
2371 | 2391 | (else |
2372 | 2392 | (io.write b (string.rep "\\" count)) |
2373 | 2393 | (write-char nxch b) |
2374 | | - (loop (read-char p) b e 0)))) |
| 2394 | + (loop (read-char p) b e 0 (update-bidi-state bds nxch))))) |
2375 | 2395 | (let ((nxch (not-eof-for delim (read-char p)))) |
2376 | 2396 | (write-char #\\ b) |
2377 | 2397 | (if (eqv? nxch #\return) |
2378 | | - (loop nxch b e 0) |
| 2398 | + (loop nxch b e 0 bds) |
2379 | 2399 | (begin |
2380 | 2400 | (write-char nxch b) |
2381 | | - (loop (read-char p) b e 0)))))) |
| 2401 | + (loop (read-char p) b e 0 (update-bidi-state bds nxch))))))) |
2382 | 2402 |
|
2383 | 2403 | ((and (eqv? c #\$) (not raw)) |
2384 | 2404 | (let* ((ex (parse-interpolate s)) |
|
2388 | 2408 | (loop (read-char p) |
2389 | 2409 | (open-output-string) |
2390 | 2410 | (list* ex (io.tostring! b) e) |
2391 | | - 0))) |
| 2411 | + 0 bds))) |
2392 | 2412 |
|
2393 | 2413 | ; convert literal \r and \r\n in strings to \n (issue #11988) |
2394 | 2414 | ((eqv? c #\return) ; \r |
2395 | 2415 | (begin |
2396 | 2416 | (if (eqv? (peek-char p) #\linefeed) ; \r\n |
2397 | 2417 | (read-char p)) |
2398 | 2418 | (write-char #\newline b) |
2399 | | - (loop (read-char p) b e 0))) |
| 2419 | + (loop (read-char p) b e 0 bds))) |
2400 | 2420 |
|
2401 | 2421 | (else |
2402 | 2422 | (write-char (not-eof-for delim c) b) |
2403 | | - (loop (read-char p) b e 0))))) |
| 2423 | + (loop (read-char p) b e 0 (update-bidi-state bds c)))))) |
2404 | 2424 |
|
2405 | 2425 | (define (not-eof-1 c) |
2406 | 2426 | (if (eof-object? c) |
|
0 commit comments