|
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)
|
|
2354 | 2370 | (let loop ((c (read-char p))
|
2355 | 2371 | (b (open-output-string))
|
2356 | 2372 | (e ())
|
2357 |
| - (quotes 0)) |
| 2373 | + (quotes 0) |
| 2374 | + (bds (make-bidi-state))) |
2358 | 2375 | (cond
|
2359 | 2376 | ((eqv? c delim)
|
2360 | 2377 | (if (< quotes n)
|
2361 |
| - (loop (read-char p) b e (+ quotes 1)) |
2362 |
| - (reverse (cons (io.tostring! b) e)))) |
| 2378 | + (loop (read-char p) b e (+ quotes 1) bds) |
| 2379 | + (begin |
| 2380 | + (if (not (bidi-state-terminated? bds)) |
| 2381 | + (error "unbalanced bidirectional formatting in string literal")) |
| 2382 | + (reverse (cons (io.tostring! b) e))))) |
2363 | 2383 |
|
2364 | 2384 | ((= quotes 1)
|
2365 | 2385 | (if (not raw) (write-char #\\ b))
|
2366 | 2386 | (write-char delim b)
|
2367 |
| - (loop c b e 0)) |
| 2387 | + (loop c b e 0 (update-bidi-state bds c))) |
2368 | 2388 |
|
2369 | 2389 | ((= quotes 2)
|
2370 | 2390 | (if (not raw) (write-char #\\ b))
|
2371 | 2391 | (write-char delim b)
|
2372 | 2392 | (if (not raw) (write-char #\\ b))
|
2373 | 2393 | (write-char delim b)
|
2374 |
| - (loop c b e 0)) |
| 2394 | + (loop c b e 0 (update-bidi-state bds c))) |
2375 | 2395 |
|
2376 | 2396 | ((eqv? c #\\)
|
2377 | 2397 | (if raw
|
|
2384 | 2404 | (io.write b (string.rep "\\" (div count 2)))
|
2385 | 2405 | (if (odd? count)
|
2386 | 2406 | (begin (write-char delim b)
|
2387 |
| - (loop (read-char p) b e 0)) |
2388 |
| - (loop nxch b e 0))) |
| 2407 | + (loop (read-char p) b e 0 bds)) |
| 2408 | + (loop nxch b e 0 bds))) |
2389 | 2409 | (else
|
2390 | 2410 | (io.write b (string.rep "\\" count))
|
2391 | 2411 | (write-char nxch b)
|
2392 |
| - (loop (read-char p) b e 0)))) |
| 2412 | + (loop (read-char p) b e 0 (update-bidi-state bds nxch))))) |
2393 | 2413 | (let ((nxch (not-eof-for delim (read-char p))))
|
2394 | 2414 | (write-char #\\ b)
|
2395 | 2415 | (if (eqv? nxch #\return)
|
2396 |
| - (loop nxch b e 0) |
| 2416 | + (loop nxch b e 0 bds) |
2397 | 2417 | (begin
|
2398 | 2418 | (write-char nxch b)
|
2399 |
| - (loop (read-char p) b e 0)))))) |
| 2419 | + (loop (read-char p) b e 0 (update-bidi-state bds nxch))))))) |
2400 | 2420 |
|
2401 | 2421 | ((and (eqv? c #\$) (not raw))
|
2402 | 2422 | (let* ((ex (parse-interpolate s))
|
|
2406 | 2426 | (loop (read-char p)
|
2407 | 2427 | (open-output-string)
|
2408 | 2428 | (list* ex (io.tostring! b) e)
|
2409 |
| - 0))) |
| 2429 | + 0 bds))) |
2410 | 2430 |
|
2411 | 2431 | ; convert literal \r and \r\n in strings to \n (issue #11988)
|
2412 | 2432 | ((eqv? c #\return) ; \r
|
2413 | 2433 | (begin
|
2414 | 2434 | (if (eqv? (peek-char p) #\linefeed) ; \r\n
|
2415 | 2435 | (read-char p))
|
2416 | 2436 | (write-char #\newline b)
|
2417 |
| - (loop (read-char p) b e 0))) |
| 2437 | + (loop (read-char p) b e 0 bds))) |
2418 | 2438 |
|
2419 | 2439 | (else
|
2420 | 2440 | (write-char (not-eof-for delim c) b)
|
2421 |
| - (loop (read-char p) b e 0))))) |
| 2441 | + (loop (read-char p) b e 0 (update-bidi-state bds c)))))) |
2422 | 2442 |
|
2423 | 2443 | (define (not-eof-1 c)
|
2424 | 2444 | (if (eof-object? c)
|
|
0 commit comments