lua: string library (len/upper/lower/rep/sub/byte/char/find/match/gmatch/gsub/format) +19 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
This commit is contained in:
@@ -651,3 +651,230 @@
|
||||
(dict-set! coroutine "yield" lua-coroutine-yield)
|
||||
(dict-set! coroutine "status" lua-coroutine-status)
|
||||
(dict-set! coroutine "wrap" lua-coroutine-wrap)
|
||||
|
||||
;; ── string library ────────────────────────────────────────────
|
||||
(define string {})
|
||||
|
||||
(define __ascii-32-126 " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~")
|
||||
|
||||
(define
|
||||
lua-string-len
|
||||
(fn (s) (len s)))
|
||||
|
||||
(define
|
||||
lua-string-upper
|
||||
(fn (s) (upcase s)))
|
||||
|
||||
(define
|
||||
lua-string-lower
|
||||
(fn (s) (downcase s)))
|
||||
|
||||
(define
|
||||
lua-string-rep
|
||||
(fn (s n)
|
||||
(cond
|
||||
((<= n 0) "")
|
||||
((= n 1) s)
|
||||
(else (str s (lua-string-rep s (- n 1)))))))
|
||||
|
||||
(define
|
||||
lua-string-sub
|
||||
(fn (&rest args)
|
||||
(let ((s (first args))
|
||||
(slen (len (first args)))
|
||||
(i (nth args 1))
|
||||
(j (if (> (len args) 2) (nth args 2) -1)))
|
||||
(let ((ni (cond
|
||||
((< i 0) (+ slen i 1))
|
||||
((= i 0) 1)
|
||||
(else i)))
|
||||
(nj (cond
|
||||
((< j 0) (+ slen j 1))
|
||||
((> j slen) slen)
|
||||
(else j))))
|
||||
(let ((ci (if (< ni 1) 1 ni))
|
||||
(cj (if (> nj slen) slen nj)))
|
||||
(cond
|
||||
((> ci cj) "")
|
||||
(else (substring s (- ci 1) cj))))))))
|
||||
|
||||
(define
|
||||
lua-string-byte
|
||||
(fn (&rest args)
|
||||
(let ((s (first args))
|
||||
(i (if (> (len args) 1) (nth args 1) 1)))
|
||||
(cond
|
||||
((or (< i 1) (> i (len s))) nil)
|
||||
(else (char-code (char-at s (- i 1))))))))
|
||||
|
||||
(define
|
||||
lua-char-one
|
||||
(fn (n)
|
||||
(cond
|
||||
((= n 9) "\t")
|
||||
((= n 10) "\n")
|
||||
((= n 13) "\r")
|
||||
((and (>= n 32) (<= n 126)) (char-at __ascii-32-126 (- n 32)))
|
||||
(else (error (str "lua: string.char out of range: " n))))))
|
||||
|
||||
(define
|
||||
lua-string-char
|
||||
(fn (&rest args)
|
||||
(cond
|
||||
((= (len args) 0) "")
|
||||
(else
|
||||
(let ((out ""))
|
||||
(begin
|
||||
(define
|
||||
loop
|
||||
(fn (i)
|
||||
(when (< i (len args))
|
||||
(begin
|
||||
(set! out (str out (lua-char-one (nth args i))))
|
||||
(loop (+ i 1))))))
|
||||
(loop 0)
|
||||
out))))))
|
||||
|
||||
;; Literal-only string.find: returns (start, end) 1-indexed or nil.
|
||||
(define
|
||||
lua-string-find
|
||||
(fn (&rest args)
|
||||
(let ((s (first args))
|
||||
(pat (nth args 1))
|
||||
(init (if (> (len args) 2) (nth args 2) 1)))
|
||||
(let ((start-i (cond
|
||||
((< init 0) (+ (len s) init 1))
|
||||
((= init 0) 1)
|
||||
(else init))))
|
||||
(let ((sub (if (<= start-i 1) s (substring s (- start-i 1) (len s)))))
|
||||
(let ((idx (index-of sub pat)))
|
||||
(cond
|
||||
((< idx 0) nil)
|
||||
(else
|
||||
(list
|
||||
(quote lua-multi)
|
||||
(+ start-i idx)
|
||||
(+ start-i idx (len pat) -1))))))))))
|
||||
|
||||
;; Literal-only string.match: returns matched substring or nil (no captures since no pattern).
|
||||
(define
|
||||
lua-string-match
|
||||
(fn (&rest args)
|
||||
(let ((s (first args)) (pat (nth args 1)))
|
||||
(let ((idx (index-of s pat)))
|
||||
(cond
|
||||
((< idx 0) nil)
|
||||
(else pat))))))
|
||||
|
||||
;; Literal-only string.gmatch: iterator producing each literal match of pat.
|
||||
(define
|
||||
lua-string-gmatch
|
||||
(fn (s pat)
|
||||
(let ((pos 0))
|
||||
(fn (&rest __)
|
||||
(cond
|
||||
((> pos (len s)) nil)
|
||||
(else
|
||||
(let ((rest-str (if (= pos 0) s (substring s pos (len s)))))
|
||||
(let ((idx (index-of rest-str pat)))
|
||||
(cond
|
||||
((< idx 0) (begin (set! pos (+ (len s) 1)) nil))
|
||||
(else
|
||||
(begin
|
||||
(set! pos (+ pos idx (len pat)))
|
||||
pat)))))))))))
|
||||
|
||||
;; Literal-only string.gsub: replace all occurrences of pat with repl (string only for now).
|
||||
(define
|
||||
lua-string-gsub
|
||||
(fn (&rest args)
|
||||
(let ((s (first args))
|
||||
(pat (nth args 1))
|
||||
(repl (nth args 2))
|
||||
(max-n (if (> (len args) 3) (nth args 3) -1)))
|
||||
(cond
|
||||
((= (len pat) 0) (list (quote lua-multi) s 0))
|
||||
(else
|
||||
(let ((out "") (pos 0) (count 0) (done false))
|
||||
(begin
|
||||
(define
|
||||
loop
|
||||
(fn ()
|
||||
(when (and (not done) (<= pos (len s)))
|
||||
(let ((rest-str (if (= pos 0) s (substring s pos (len s)))))
|
||||
(let ((idx (index-of rest-str pat)))
|
||||
(cond
|
||||
((< idx 0)
|
||||
(begin
|
||||
(set! out (str out rest-str))
|
||||
(set! done true)))
|
||||
((and (>= max-n 0) (>= count max-n))
|
||||
(begin
|
||||
(set! out (str out rest-str))
|
||||
(set! done true)))
|
||||
(else
|
||||
(let ((before (substring rest-str 0 idx)))
|
||||
(begin
|
||||
(set! out (str out before (if (= (type-of repl) "string") repl (str repl))))
|
||||
(set! pos (+ pos idx (len pat)))
|
||||
(set! count (+ count 1))
|
||||
(loop))))))))))
|
||||
(loop)
|
||||
(list (quote lua-multi) out count))))))))
|
||||
|
||||
;; Basic string.format: %s %d %f (%%.Nf ignored), %%.
|
||||
(define
|
||||
lua-format-int
|
||||
(fn (n)
|
||||
(cond
|
||||
((= (type-of n) "number") (str (floor n)))
|
||||
(else (str n)))))
|
||||
|
||||
(define
|
||||
lua-string-format
|
||||
(fn (&rest args)
|
||||
(let ((fmt (first args)) (vals (rest args)))
|
||||
(let ((out "") (i 0) (vi 0))
|
||||
(begin
|
||||
(define
|
||||
loop
|
||||
(fn ()
|
||||
(when (< i (len fmt))
|
||||
(let ((c (char-at fmt i)))
|
||||
(cond
|
||||
((and (= c "%") (< (+ i 1) (len fmt)))
|
||||
(let ((spec (char-at fmt (+ i 1))))
|
||||
(cond
|
||||
((= spec "%")
|
||||
(begin (set! out (str out "%")) (set! i (+ i 2)) (loop)))
|
||||
((= spec "s")
|
||||
(begin
|
||||
(set! out (str out (lua-concat-coerce (nth vals vi))))
|
||||
(set! vi (+ vi 1)) (set! i (+ i 2)) (loop)))
|
||||
((= spec "d")
|
||||
(begin
|
||||
(set! out (str out (lua-format-int (nth vals vi))))
|
||||
(set! vi (+ vi 1)) (set! i (+ i 2)) (loop)))
|
||||
((= spec "f")
|
||||
(begin
|
||||
(set! out (str out (str (nth vals vi))))
|
||||
(set! vi (+ vi 1)) (set! i (+ i 2)) (loop)))
|
||||
(else
|
||||
(begin (set! out (str out c)) (set! i (+ i 1)) (loop))))))
|
||||
(else
|
||||
(begin (set! out (str out c)) (set! i (+ i 1)) (loop))))))))
|
||||
(loop)
|
||||
out)))))
|
||||
|
||||
(dict-set! string "len" lua-string-len)
|
||||
(dict-set! string "upper" lua-string-upper)
|
||||
(dict-set! string "lower" lua-string-lower)
|
||||
(dict-set! string "rep" lua-string-rep)
|
||||
(dict-set! string "sub" lua-string-sub)
|
||||
(dict-set! string "byte" lua-string-byte)
|
||||
(dict-set! string "char" lua-string-char)
|
||||
(dict-set! string "find" lua-string-find)
|
||||
(dict-set! string "match" lua-string-match)
|
||||
(dict-set! string "gmatch" lua-string-gmatch)
|
||||
(dict-set! string "gsub" lua-string-gsub)
|
||||
(dict-set! string "format" lua-string-format)
|
||||
|
||||
Reference in New Issue
Block a user