# Interop with native JavaScript

## Goal
Provide the ways to interact with native JavaScript.

## Type-safe Declarations

### Annotation `native`
TODO

### Annotation `nativeInvoke`

Calls to functions annotated by `nativeInvoke` will be translated to calls of receiver with the arguments provided for original call.

Applicable to:
* member functions of native declarations
* non-member extension functions

Example:

```kotlin
native
class A {
    nativeInvoke
    fun invoke(): String = noImpl

    nativeInvoke
    fun foo(a: Int): Int = noImpl
}

fun A.bar(a: String): Int = noImpl


fun test(baz: A) {
	baz()
	baz.invoke()
	baz.foo(1)
	baz.bar("str")
}
```

Function `test` will be translated to:

```js
...
test: function (baz) {
	foo()
	foo()
	foo(1)
	foo("str")
}
...
```

### Annotation `nativeGetter`

Calls to functions annotated by `nativeGetter` will be translated to square/index operation on the receiver with the argument provided for original call.

Applicable to:
* member functions of native declarations
* non-member extension functions

Requirements:
* must have exactly one argument
* type of the argument must be `String` or subtype of `Number`
* default values are prohibited
* return type must be nullable

Example:

```kotlin
native
class A {
    nativeGetter
    fun get(a: String): String? = noImpl

    nativeGetter
    fun foo(a: Int): Int? = noImpl
}

class B

nativeGetter
fun B.get(a: String): Int? = noImpl

nativeGetter
fun B.bar(a: Int): Int? = noImpl

fun test(a: A, b: B) {
	a["foo"]
	a.get("bar")
	a.foo(1)
	b["foo"]
	b.get("bar")
	b.bar(1)
}
```

Function `test` will be translated to:


```js
...
test: function (a, b) {
	a["foo"]
	a["bar"]
	a[1]
	b["foo"]
	b["bar"]
	b[1]
}
...
```


### Annotation `nativeSetter`

Calls of functions annotated by `nativeSetter` will be translated to assignment of the second argument to the receiver
indexed (with square/index operation) with the first argument.

Applicable to:
* member functions of native declarations
* non-member extension functions

Requirements:
* must have exactly two arguments
* type of the first argument must be `String` or subtype of `Number`
* default values are prohibited
* the return type is either `Unit` or a supertype of the second parameter's type

Example:

```kotlin
native
class A {
    nativeSetter
    fun set(a: String, v: Any) {}

    nativeSetter
    fun foo(a: Int, v: A) {}
}

class B

nativeSetter
fun B.set(a: String, v: B) {}

nativeSetter
fun B.bar(a: String, v: B?) {}

fun test(a: A, b: B) {
	a["foo"] = "text"
	a.set("bar", "value")
	a.foo(1, A())
	b["foo"] = B()
	b.set("bar", b)
	b.bar("a", null)
}
```

Function `test` will be translated to:

```js
...
test: function (a, b) {
	a["foo"] = "text"
	a["bar"] = "value"
	a[1] = A()
	b["foo"] = B()
	b["bar"] = b
	b["a"] = null
}
...
```

## Function `js`

Argument of `js` function is parsed as JavaScript code and injected directly into the JavaScript code generated by the compiler.

Requirements:
* the argument should be a compile time constant of type `String`

Example:

```kotlin
fun test1() {
	js("console.log('Hello')")
}

fun test2(a: String) = js(""" 
	var r = foo(a);
	return r;
""")
```

is translated to:
```js
function test1() {
	console.log('Hello')	
}

function test2(a) {
	var r = foo(a);
	return r;
}
```

## Dynamic types

All dynamic calls with explicit names (regular and infix function calls, and property calls) are translated "as is", without mangling.
Additionally, many operations when applied to a receiver of type `dynamic` are translated "as is", instead of by convention.

Operations translated "as is" to JavaScript:
* binary: `+`, `-`, `*`, `/`, `%`, `>`, `<` `>=`, `<=`, `==`, `!=`, `===`, `!==`, `&&`, `||`
* unary
 * prefix: `-`, `+`, `!`
 * prefix and postfix: `++`, `--`
* assignments: `+=`, `-=`, `*=`, `/=`, `%=`
* indexed access:
 * read: `d[a]`, more than one argument is an error
 * write: `d[a1] = a2`, more than one argument in `[]` is an error
* `in` and `!in` are forbidden, an error is reported

Note:
* `..` is translated to a call to `rangeTo`
* `~`, `|`, `&` and `^` are not supported (there's no Kotlin code that translates to these operations)