Lower typed Int helpers to Kotlin
ober
ad51de9795bb640e445deeb223f052672c80581c
--- a/lib/jerboa/typed/checker.ss +++ b/lib/jerboa/typed/checker.ss @@ -403,6 +403,9 @@ (cons 'int32->string (make-typed-call-sig (list 'Int32) 'String '() 'jvm-to-string '())) + (cons 'int->string + (make-typed-call-sig (list 'Int) 'String '() + 'jvm-to-string '())) (cons 'string-take (make-typed-call-sig (list 'String 'Int32) 'String '() 'jvm-string-take '())) @@ -1430,6 +1433,25 @@ 'jvm-to-int32 'int32 (list arg-ir) '())) (append errors operand-errors)))))) + (def (infer-to-int args env type-names expr) + ;; JVM/Android interop: explicitly widen or normalize a numeric value to + ;; Kotlin Long, represented by Typed Jerboa's Int. + (if (not (= (length args) 1)) + (values #f + (list (error-at expr 'bad-primitive-arity + "int needs exactly one operand" + expr))) + (let-values ([(arg-ir errors) (infer-expression (car args) env type-names)]) + (let* ([operand-errors + (operand-type-errors 'numeric (list (ir-type arg-ir)) + (list expr) expr)] + [ok? (and arg-ir (null? errors) (null? operand-errors))]) + (values + (and ok? + (make-typed-ir-call 'Int (expr-source expr) + 'jvm-to-int 'int (list arg-ir) '())) + (append errors operand-errors)))))) + (def (infer-float-array args env type-names expr) (let-values ([(arg-irs errors) (infer-args args env type-names)]) (let* ([types (ir-list-types arg-irs)] @@ -1849,7 +1871,7 @@ (infer-if args env type-names expr)] [(match) (infer-match args env type-names expr)] - [(+ - * /) + [(+ - * / mod) (infer-arithmetic head args env type-names expr)] [(= < <= > >=) (infer-comparison head args env type-names expr)] @@ -1873,6 +1895,8 @@ (infer-to-float32 args env type-names expr)] [(int32) (infer-to-int32 args env type-names expr)] + [(int) + (infer-to-int args env type-names expr)] [(float-array) (infer-float-array args env type-names expr)] [(bytes-build) --- a/lib/jerboa/typed/kotlin/lower.ss +++ b/lib/jerboa/typed/kotlin/lower.ss @@ -149,6 +149,7 @@ [(-) "-"] [(*) "*"] [(/) "/"] + [(mod) "%"] [else (error 'arith-op "unsupported arithmetic op" op)])) (def (cmp-op op) @@ -220,6 +221,11 @@ (memq (kt-lit-type (car args)) '(Nat Int Int32))) (make-kt-lit 'Int32 (kt-lit-value (car args))) (make-kt-member-call (car args) 'toInt '()))] + [(jvm-to-int) + (if (and (kt-lit? (car args)) + (memq (kt-lit-type (car args)) '(Nat Int Int32))) + (make-kt-lit 'Int (kt-lit-value (car args))) + (make-kt-member-call (car args) 'toLong '()))] [(jvm-to-string) (make-kt-member-call (car args) 'toString '())] [(string-length) --- a/tests/test-typed-kotlin.ss +++ b/tests/test-typed-kotlin.ss @@ -278,6 +278,28 @@ (test-contains "String length lowers to Kotlin length" string-length-kotlin "text.length.toULong()") +(define duration-form + '(typed-library (sample typed duration) + (export formatActivityDuration) + (def (formatActivityDuration (ms : Int)) : String + (let ((safe (if (< ms (int 0)) (int 0) ms))) + (if (< safe (int 1000)) + (string-append (int->string safe) " ms") + (let ((seconds (/ safe (int 1000))) + (tenths (mod (/ safe (int 100)) (int 10)))) + (string-append + (int->string seconds) + (string-append "." (string-append (int->string tenths) " s"))))))))) + +(define duration-kotlin (typed-library-form->kotlin-string duration-form)) + +(test-contains "Int conversion lowers to Kotlin Long literal" duration-kotlin + "if ((ms < 0L)) 0L else ms") +(test-contains "Int to string lowers to Kotlin toString" duration-kotlin + "safe.toString()") +(test-contains "mod lowers to Kotlin remainder operator" duration-kotlin + "((safe / 100L) % 10L)") + (define note-form '(typed-library (sample typed notes) (export appendNote)