|
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