Add typed Kotlin string normalization helpers

ober

2b25220c60205e0d94013b533fad1ed8091d483f

diff --git a/lib/jerboa/typed/checker.ss b/lib/jerboa/typed/checker.ss
index e2d9169..5250232 100644
--- a/lib/jerboa/typed/checker.ss
+++ b/lib/jerboa/typed/checker.ss
@@ -409,6 +409,18 @@
       (cons 'string-lowercase
             (make-typed-call-sig (list 'String) 'String '()
               'jvm-string-lowercase '()))
+      (cons 'string-uppercase
+            (make-typed-call-sig (list 'String) 'String '()
+              'jvm-string-uppercase '()))
+      (cons 'string-trim
+            (make-typed-call-sig (list 'String) 'String '()
+              'jvm-string-trim '()))
+      (cons 'string-replace-regex
+            (make-typed-call-sig (list 'String 'String 'String) 'String '()
+              'jvm-string-replace-regex '()))
+      (cons 'string-filter-letter-or-digit
+            (make-typed-call-sig (list 'String) 'String '()
+              'jvm-string-filter-letter-or-digit '()))
       (cons 'string-contains?
             (make-typed-call-sig (list 'String 'String) 'Bool '()
               'jvm-string-contains '()))
diff --git a/lib/jerboa/typed/kotlin/ast.ss b/lib/jerboa/typed/kotlin/ast.ss
index 4f7c5aa..496b1f4 100644
--- a/lib/jerboa/typed/kotlin/ast.ss
+++ b/lib/jerboa/typed/kotlin/ast.ss
@@ -69,6 +69,9 @@
     kt-index-get? make-kt-index-get
     kt-index-get-target kt-index-get-index
 
+    kt-lambda? make-kt-lambda
+    kt-lambda-params kt-lambda-body
+
     kt-binary? make-kt-binary
     kt-binary-op kt-binary-left kt-binary-right
 
@@ -127,6 +130,7 @@
   (defstruct kt-member-call (target name args))
   (defstruct kt-member-get (target name))
   (defstruct kt-index-get (target index))
+  (defstruct kt-lambda (params body))
   (defstruct kt-binary (op left right))
   (defstruct kt-unary (op expr))
   (defstruct kt-if (test then else))
diff --git a/lib/jerboa/typed/kotlin/lower.ss b/lib/jerboa/typed/kotlin/lower.ss
index 6c9b1fd..d10a00f 100644
--- a/lib/jerboa/typed/kotlin/lower.ss
+++ b/lib/jerboa/typed/kotlin/lower.ss
@@ -228,6 +228,25 @@
          (make-kt-member-call (car args) 'padStart (cdr args))]
         [(jvm-string-lowercase)
          (make-kt-member-call (car args) 'lowercase '())]
+        [(jvm-string-uppercase)
+         (make-kt-member-call (car args) 'uppercase '())]
+        [(jvm-string-trim)
+         (make-kt-member-call (car args) 'trim '())]
+        [(jvm-string-replace-regex)
+         (make-kt-member-call
+           (car args)
+           'replace
+           (list
+             (make-kt-new (make-kt-type 'Regex #f '()) (list (cadr args)))
+             (caddr args)))]
+        [(jvm-string-filter-letter-or-digit)
+         (make-kt-member-call
+           (car args)
+           'filter
+           (list
+             (make-kt-lambda
+               '(ch)
+               (make-kt-member-call (kt-name1 'ch) 'isLetterOrDigit '()))))]
         [(jvm-string-contains)
          (make-kt-member-call (car args) 'contains (cdr args))]
         [(jvm-string-blank)
diff --git a/lib/jerboa/typed/kotlin/print.ss b/lib/jerboa/typed/kotlin/print.ss
index 2d9e7f1..e87b9a3 100644
--- a/lib/jerboa/typed/kotlin/print.ss
+++ b/lib/jerboa/typed/kotlin/print.ss
@@ -232,6 +232,13 @@
          "["
          (kotlin-expr->string (kt-index-get-index expr))
          "]")]
+      [(kt-lambda? expr)
+       (string-append
+         "{ "
+         (join-strings (map kotlin-symbol-name (kt-lambda-params expr)) ", ")
+         " -> "
+         (kotlin-expr->string (kt-lambda-body expr))
+         " }")]
       [(kt-binary? expr)
        (parenthesize
          (string-append
diff --git a/tests/test-typed-kotlin.ss b/tests/test-typed-kotlin.ss
index cecf84c..57cbc72 100644
--- a/tests/test-typed-kotlin.ss
+++ b/tests/test-typed-kotlin.ss
@@ -50,6 +50,12 @@
 (test "string literal escapes"
   (kotlin-string-literal "a\n\"b\"\\c")
   "\"a\\n\\\"b\\\"\\\\c\"")
+(test "lambda expression printer"
+  (kotlin-expr->string
+    (make-kt-lambda
+      '(ch)
+      (make-kt-member-call (make-kt-name '(ch)) 'isLetterOrDigit '())))
+  "{ ch -> ch.isLetterOrDigit() }")
 
 (define ast-file
   (make-kt-file
@@ -270,5 +276,31 @@
 (test-contains "String blank lowers to Kotlin isBlank" note-kotlin
   "existing.isBlank()")
 
+(define ocr-string-form
+  '(typed-library (sample typed ocrstrings)
+     (export normalizeOcr compact)
+     (def (normalizeOcr (value : String)) : String
+       (string-replace-regex
+         (string-trim
+           (string-replace-regex
+             (string-uppercase value)
+             "[^A-Z0-9]+"
+             " "))
+         "\\s+"
+         " "))
+     (def (compact (value : String)) : String
+       (string-filter-letter-or-digit (string-lowercase value)))))
+
+(define ocr-string-kotlin (typed-library-form->kotlin-string ocr-string-form))
+
+(test-contains "String uppercase lowers to Kotlin uppercase" ocr-string-kotlin
+  "value.uppercase()")
+(test-contains "String regex replace lowers to Kotlin Regex replace" ocr-string-kotlin
+  ".replace(Regex(\"[^A-Z0-9]+\"), \" \")")
+(test-contains "String trim lowers to Kotlin trim" ocr-string-kotlin
+  ".trim()")
+(test-contains "String filter letter-or-digit lowers to Kotlin filter lambda" ocr-string-kotlin
+  "value.lowercase().filter({ ch -> ch.isLetterOrDigit() })")
+
 (printf "typed-kotlin tests: ~a passed, ~a failed~%" pass fail)
 (when (> fail 0) (exit 1))