|
219 | 219 |
|
220 | 220 | (define (newline? c) (eqv? c #\newline))
|
221 | 221 |
|
222 |
| -(define (skip-to-eol port) |
223 |
| - (let ((c (peek-char port))) |
224 |
| - (cond ((eof-object? c) c) |
225 |
| - ((eqv? c #\newline) c) |
226 |
| - (else (read-char port) |
227 |
| - (skip-to-eol port))))) |
228 |
| - |
229 | 222 | (define (op-or-sufchar? c) (or (op-suffix-char? c) (opchar? c)))
|
230 | 223 |
|
231 | 224 | (define (read-operator port c0 (postfix? #f))
|
|
486 | 479 | (pair? (cadr t)) (eq? (car (cadr t)) 'core)
|
487 | 480 | (memq (cadadr t) '(@int128_str @uint128_str @big_str))))
|
488 | 481 |
|
| 482 | +(define (make-bidi-state) '(0 . 0)) |
| 483 | + |
| 484 | +(define (update-bidi-state st c) |
| 485 | + (case c |
| 486 | + ((#\U202A #\U202B #\U202D #\U202E) (cons (+ (car st) 1) (cdr st))) ;; LRE RLE LRO RLO |
| 487 | + ((#\U2066 #\U2067 #\U2068) (cons (car st) (+ (cdr st) 1))) ;; LRI RLI FSI |
| 488 | + ((#\U202C) (cons (- (car st) 1) (cdr st))) ;; PDF |
| 489 | + ((#\U2069) (cons (car st) (- (cdr st) 1))) ;; PDI |
| 490 | + ((#\newline) '(0 . 0)) |
| 491 | + (else st))) |
| 492 | + |
| 493 | +(define (bidi-state-terminated? st) (equal? st '(0 . 0))) |
| 494 | + |
| 495 | +(define (skip-line-comment port) |
| 496 | + (let ((c (peek-char port))) |
| 497 | + (cond ((eof-object? c) c) |
| 498 | + ((eqv? c #\newline) c) |
| 499 | + (else (read-char port) |
| 500 | + (skip-line-comment port))))) |
| 501 | + |
| 502 | +(define (skip-multiline-comment port count bds) |
| 503 | + (let ((c (read-char port))) |
| 504 | + (if (eof-object? c) |
| 505 | + (error "incomplete: unterminated multi-line comment #= ... =#") ; NOTE: changing this may affect code in base/client.jl |
| 506 | + (if (eqv? c #\=) |
| 507 | + (let ((c (peek-char port))) |
| 508 | + (if (eqv? c #\#) |
| 509 | + (begin |
| 510 | + (read-char port) |
| 511 | + (if (> count 1) |
| 512 | + (skip-multiline-comment port (- count 1) bds) |
| 513 | + (if (not (bidi-state-terminated? bds)) |
| 514 | + (error "unbalanced bidirectional formatting in comment")))) |
| 515 | + (skip-multiline-comment port count (update-bidi-state bds c)))) |
| 516 | + (if (eqv? c #\#) |
| 517 | + (skip-multiline-comment port |
| 518 | + (if (eqv? (peek-char port) #\=) |
| 519 | + (begin (read-char port) |
| 520 | + (+ count 1)) |
| 521 | + count) |
| 522 | + bds) |
| 523 | + (skip-multiline-comment port count (update-bidi-state bds c))))))) |
| 524 | + |
489 | 525 | ;; skip to end of comment, starting at #: either #...<eol> or #= .... =#.
|
490 | 526 | (define (skip-comment port)
|
491 |
| - (define (skip-multiline-comment port count) |
492 |
| - (let ((c (read-char port))) |
493 |
| - (if (eof-object? c) |
494 |
| - (error "incomplete: unterminated multi-line comment #= ... =#") ; NOTE: changing this may affect code in base/client.jl |
495 |
| - (begin (if (eqv? c #\=) |
496 |
| - (let ((c (peek-char port))) |
497 |
| - (if (eqv? c #\#) |
498 |
| - (begin |
499 |
| - (read-char port) |
500 |
| - (if (> count 1) |
501 |
| - (skip-multiline-comment port (- count 1)))) |
502 |
| - (skip-multiline-comment port count))) |
503 |
| - (if (eqv? c #\#) |
504 |
| - (skip-multiline-comment port |
505 |
| - (if (eqv? (peek-char port) #\=) |
506 |
| - (begin (read-char port) |
507 |
| - (+ count 1)) |
508 |
| - count)) |
509 |
| - (skip-multiline-comment port count))))))) |
510 |
| - |
511 | 527 | (read-char port) ; read # that was already peeked
|
512 | 528 | (if (eqv? (peek-char port) #\=)
|
513 | 529 | (begin (read-char port) ; read initial =
|
514 |
| - (skip-multiline-comment port 1)) |
515 |
| - (skip-to-eol port))) |
| 530 | + (skip-multiline-comment port 1 (make-bidi-state))) |
| 531 | + (skip-line-comment port))) |
516 | 532 |
|
517 | 533 | (define (skip-ws-and-comments port)
|
518 | 534 | (skip-ws port #t)
|
|
2221 | 2237 | (let loop ((c (read-char p))
|
2222 | 2238 | (b (open-output-string))
|
2223 | 2239 | (e ())
|
2224 |
| - (quotes 0)) |
| 2240 | + (quotes 0) |
| 2241 | + (bds (make-bidi-state))) |
2225 | 2242 | (cond
|
2226 | 2243 | ((eqv? c delim)
|
2227 | 2244 | (if (< quotes n)
|
2228 |
| - (loop (read-char p) b e (+ quotes 1)) |
2229 |
| - (reverse (cons (io.tostring! b) e)))) |
| 2245 | + (loop (read-char p) b e (+ quotes 1) bds) |
| 2246 | + (begin |
| 2247 | + (if (not (bidi-state-terminated? bds)) |
| 2248 | + (error "unbalanced bidirectional formatting in string literal")) |
| 2249 | + (reverse (cons (io.tostring! b) e))))) |
2230 | 2250 |
|
2231 | 2251 | ((= quotes 1)
|
2232 | 2252 | (if (not raw) (write-char #\\ b))
|
2233 | 2253 | (write-char delim b)
|
2234 |
| - (loop c b e 0)) |
| 2254 | + (loop c b e 0 (update-bidi-state bds c))) |
2235 | 2255 |
|
2236 | 2256 | ((= quotes 2)
|
2237 | 2257 | (if (not raw) (write-char #\\ b))
|
2238 | 2258 | (write-char delim b)
|
2239 | 2259 | (if (not raw) (write-char #\\ b))
|
2240 | 2260 | (write-char delim b)
|
2241 |
| - (loop c b e 0)) |
| 2261 | + (loop c b e 0 (update-bidi-state bds c))) |
2242 | 2262 |
|
2243 | 2263 | ((eqv? c #\\)
|
2244 | 2264 | (if raw
|
|
2251 | 2271 | (io.write b (string.rep "\\" (div count 2)))
|
2252 | 2272 | (if (odd? count)
|
2253 | 2273 | (begin (write-char delim b)
|
2254 |
| - (loop (read-char p) b e 0)) |
2255 |
| - (loop nxch b e 0))) |
| 2274 | + (loop (read-char p) b e 0 bds)) |
| 2275 | + (loop nxch b e 0 bds))) |
2256 | 2276 | (else
|
2257 | 2277 | (io.write b (string.rep "\\" count))
|
2258 | 2278 | (write-char nxch b)
|
2259 |
| - (loop (read-char p) b e 0)))) |
| 2279 | + (loop (read-char p) b e 0 (update-bidi-state bds nxch))))) |
2260 | 2280 | (let ((nxch (not-eof-for delim (read-char p))))
|
2261 | 2281 | (write-char #\\ b)
|
2262 | 2282 | (write-char nxch b)
|
2263 |
| - (loop (read-char p) b e 0)))) |
| 2283 | + (loop (read-char p) b e 0 (update-bidi-state bds nxch))))) |
2264 | 2284 |
|
2265 | 2285 | ((and (eqv? c #\$) (not raw))
|
2266 | 2286 | (let* ((ex (parse-interpolate s))
|
|
2270 | 2290 | (loop (read-char p)
|
2271 | 2291 | (open-output-string)
|
2272 | 2292 | (list* ex (io.tostring! b) e)
|
2273 |
| - 0))) |
| 2293 | + 0 bds))) |
2274 | 2294 |
|
2275 | 2295 | ; convert literal \r and \r\n in strings to \n (issue #11988)
|
2276 | 2296 | ((eqv? c #\return) ; \r
|
2277 | 2297 | (begin
|
2278 | 2298 | (if (eqv? (peek-char p) #\linefeed) ; \r\n
|
2279 | 2299 | (read-char p))
|
2280 | 2300 | (write-char #\newline b)
|
2281 |
| - (loop (read-char p) b e 0))) |
| 2301 | + (loop (read-char p) b e 0 bds))) |
2282 | 2302 |
|
2283 | 2303 | (else
|
2284 | 2304 | (write-char (not-eof-for delim c) b)
|
2285 |
| - (loop (read-char p) b e 0))))) |
| 2305 | + (loop (read-char p) b e 0 (update-bidi-state bds c)))))) |
2286 | 2306 |
|
2287 | 2307 | (define (not-eof-1 c)
|
2288 | 2308 | (if (eof-object? c)
|
|
0 commit comments