Add typed Kotlin member externs

ober

a62bac2471f691b7087ea3594db3d375b2097cfd

diff --git a/lib/jerboa/typed/checker.ss b/lib/jerboa/typed/checker.ss
index 2084e08..a6ae91e 100644
--- a/lib/jerboa/typed/checker.ss
+++ b/lib/jerboa/typed/checker.ss
@@ -365,13 +365,20 @@
 
   (def (extern-signature decl)
     (and (typed-extern? decl)
-         (cons (typed-extern-name decl)
-               (make-typed-call-sig
-                 (map typed-param-type (typed-extern-params decl))
-                 (typed-extern-return-type decl)
-                 '()
-                 'kotlin-call
-                 (list (cons 'path (typed-extern-kotlin-path decl)))))))
+         (let* ([target (typed-extern-kotlin-path decl)]
+                [kind-entry (assq 'kind target)]
+                [kind (and kind-entry (cdr kind-entry))])
+           (cons (typed-extern-name decl)
+                 (make-typed-call-sig
+                   (map typed-param-type (typed-extern-params decl))
+                   (typed-extern-return-type decl)
+                   '()
+                   (case kind
+                     [(call) 'kotlin-call]
+                     [(member-call) 'kotlin-member-call]
+                     [(member-get) 'kotlin-member-get]
+                     [else 'kotlin-call])
+                   target)))))
 
   (def builtin-call-signatures
     (list
diff --git a/lib/jerboa/typed/core.ss b/lib/jerboa/typed/core.ss
index 440f410..47d2402 100644
--- a/lib/jerboa/typed/core.ss
+++ b/lib/jerboa/typed/core.ss
@@ -134,6 +134,8 @@
       log2
       debug-string
       kotlin-call
+      kotlin-member-call
+      kotlin-member-get
       jvm-pair
       jvm-pair-first
       jvm-pair-second
diff --git a/lib/jerboa/typed/kotlin/lower.ss b/lib/jerboa/typed/kotlin/lower.ss
index 3cb4c2d..5f8e703 100644
--- a/lib/jerboa/typed/kotlin/lower.ss
+++ b/lib/jerboa/typed/kotlin/lower.ss
@@ -614,6 +614,15 @@
              (make-kt-lit 'Char #\0)))]
         [(kotlin-call)
          (make-kt-call (make-kt-name (info-ref info 'path (list operator))) args)]
+        [(kotlin-member-call)
+         (make-kt-member-call
+           (car args)
+           (info-ref info 'member operator)
+           (cdr args))]
+        [(kotlin-member-get)
+         (make-kt-member-get
+           (car args)
+           (info-ref info 'member operator))]
         [(record-ctor)
          (make-kt-new
            (make-kt-type (info-ref info 'record operator) #f '())
diff --git a/lib/jerboa/typed/parser.ss b/lib/jerboa/typed/parser.ss
index ccc33c0..baad2c7 100644
--- a/lib/jerboa/typed/parser.ss
+++ b/lib/jerboa/typed/parser.ss
@@ -427,13 +427,26 @@
   (def (parse-kotlin-call-target form)
     (let ([form (strip-source-annotations form)])
       (expect-proper-list 'parse-typed-extern form)
-      (unless (and (>= (length form) 2)
-                   (eq? (car form) 'kotlin-call)
-                   (symbol-list? (cdr form)))
-        (error 'parse-typed-extern
-          "expected (kotlin-call PackageOrObject function)"
-          form))
-      (cdr form)))
+      (cond
+        [(and (>= (length form) 2)
+              (eq? (car form) 'kotlin-call)
+              (symbol-list? (cdr form)))
+         (list (cons 'kind 'call)
+               (cons 'path (cdr form)))]
+        [(and (= (length form) 2)
+              (eq? (car form) 'kotlin-member-call)
+              (symbol? (cadr form)))
+         (list (cons 'kind 'member-call)
+               (cons 'member (cadr form)))]
+        [(and (= (length form) 2)
+              (eq? (car form) 'kotlin-member-get)
+              (symbol? (cadr form)))
+         (list (cons 'kind 'member-get)
+               (cons 'member (cadr form)))]
+        [else
+         (error 'parse-typed-extern
+          "expected (kotlin-call PackageOrObject function), (kotlin-member-call method), or (kotlin-member-get property)"
+          form)])))
 
   (def (parse-extern form)
     (let* ([source (datum-source form)]
diff --git a/tests/test-typed-kotlin.ss b/tests/test-typed-kotlin.ss
index 7b0b494..c6df4e0 100644
--- a/tests/test-typed-kotlin.ss
+++ b/tests/test-typed-kotlin.ss
@@ -271,6 +271,47 @@
   extern-kotlin
   "return BoxTypes.resolve(context, raw)")
 
+(define member-extern-form
+  '(typed-library (sample typed memberextern)
+     (export width copyPixels)
+     (type Bitmap)
+     (type Int32)
+     (type IntArray)
+     (extern (bitmapWidth (bitmap : Bitmap)) : Int32
+       (kotlin-member-get width))
+     (extern (bitmapGetPixels (bitmap : Bitmap)
+                              (pixels : IntArray)
+                              (offset : Int32)
+                              (stride : Int32)
+                              (x : Int32)
+                              (y : Int32)
+                              (width : Int32)
+                              (height : Int32)) : Unit
+       (kotlin-member-call getPixels))
+     (def (width (bitmap : Bitmap)) : Int32
+       (bitmapWidth bitmap))
+     (def (copyPixels (bitmap : Bitmap) (pixels : IntArray)) : Unit
+       (bitmapGetPixels
+         bitmap
+         pixels
+         (int32 0)
+         (bitmapWidth bitmap)
+         (int32 0)
+         (int32 0)
+         (bitmapWidth bitmap)
+         (int32 1)))))
+
+(define member-extern-kotlin
+  (typed-library-form->kotlin-string member-extern-form))
+
+(test-contains "extern Kotlin member get lowers to property access"
+  member-extern-kotlin
+  "return bitmap.width")
+
+(test-contains "extern Kotlin member call lowers to receiver method call"
+  member-extern-kotlin
+  "bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, 1)")
+
 (define geometry-form
   '(typed-library (sample typed geometry)
      (export make-SsdCell SsdCell? SsdCell-x SsdCell-y SsdCell-w SsdCell-h