diff --git a/README.md b/README.md
index 50a916d2c..0899f77cc 100644
--- a/README.md
+++ b/README.md
@@ -89,7 +89,16 @@ submit a feature request if you want something to be implemented first.
* ### [kmath-ast](kmath-ast)
>
>
-> **Maturity**: EXPERIMENTAL
+> **Maturity**: PROTOTYPE
+>
+> **Features:**
+> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
+> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
+> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
+> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
+> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
+> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
+
* ### [kmath-commons](kmath-commons)
@@ -122,7 +131,7 @@ submit a feature request if you want something to be implemented first.
* ### [kmath-dimensions](kmath-dimensions)
>
>
-> **Maturity**: EXPERIMENTAL
+> **Maturity**: PROTOTYPE
* ### [kmath-ejml](kmath-ejml)
diff --git a/docs/templates/ARTIFACT-TEMPLATE.md b/docs/templates/ARTIFACT-TEMPLATE.md
index c77948d4b..d46a431bd 100644
--- a/docs/templates/ARTIFACT-TEMPLATE.md
+++ b/docs/templates/ARTIFACT-TEMPLATE.md
@@ -14,7 +14,7 @@
> maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
> maven { url 'https://dl.bintray.com/mipt-npm/dev' }
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
-
+>
> }
>
> dependencies {
diff --git a/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt
similarity index 66%
rename from examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt
rename to examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt
index a4806ed68..6acaca84d 100644
--- a/examples/src/main/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt
+++ b/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt
@@ -4,13 +4,19 @@ import kscience.kmath.asm.compile
import kscience.kmath.expressions.Expression
import kscience.kmath.expressions.expressionInField
import kscience.kmath.expressions.invoke
+import kscience.kmath.expressions.symbol
import kscience.kmath.operations.Field
import kscience.kmath.operations.RealField
+import org.openjdk.jmh.annotations.Benchmark
+import org.openjdk.jmh.annotations.Scope
+import org.openjdk.jmh.annotations.State
import kotlin.random.Random
-import kotlin.system.measureTimeMillis
+@State(Scope.Benchmark)
internal class ExpressionsInterpretersBenchmark {
private val algebra: Field = RealField
+
+ @Benchmark
fun functionalExpression() {
val expr = algebra.expressionInField {
symbol("x") * const(2.0) + const(2.0) / symbol("x") - const(16.0)
@@ -19,6 +25,7 @@ internal class ExpressionsInterpretersBenchmark {
invokeAndSum(expr)
}
+ @Benchmark
fun mstExpression() {
val expr = algebra.mstInField {
symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
@@ -27,6 +34,7 @@ internal class ExpressionsInterpretersBenchmark {
invokeAndSum(expr)
}
+ @Benchmark
fun asmExpression() {
val expr = algebra.mstInField {
symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0)
@@ -35,6 +43,13 @@ internal class ExpressionsInterpretersBenchmark {
invokeAndSum(expr)
}
+ @Benchmark
+ fun rawExpression() {
+ val x by symbol
+ val expr = Expression { args -> args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 }
+ invokeAndSum(expr)
+ }
+
private fun invokeAndSum(expr: Expression) {
val random = Random(0)
var sum = 0.0
@@ -46,35 +61,3 @@ internal class ExpressionsInterpretersBenchmark {
println(sum)
}
}
-
-/**
- * This benchmark compares basically evaluation of simple function with MstExpression interpreter, ASM backend and
- * core FunctionalExpressions API.
- *
- * The expected rating is:
- *
- * 1. ASM.
- * 2. MST.
- * 3. FE.
- */
-fun main() {
- val benchmark = ExpressionsInterpretersBenchmark()
-
- val fe = measureTimeMillis {
- benchmark.functionalExpression()
- }
-
- println("fe=$fe")
-
- val mst = measureTimeMillis {
- benchmark.mstExpression()
- }
-
- println("mst=$mst")
-
- val asm = measureTimeMillis {
- benchmark.asmExpression()
- }
-
- println("asm=$asm")
-}
diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/ArrayBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/ArrayBenchmark.kt
index 8c44135fb..ebf31a590 100644
--- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/ArrayBenchmark.kt
+++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/ArrayBenchmark.kt
@@ -16,17 +16,13 @@ internal class ArrayBenchmark {
@Benchmark
fun benchmarkBufferRead() {
var res = 0
- for (i in 1..size) res += arrayBuffer.get(
- size - i
- )
+ for (i in 1..size) res += arrayBuffer[size - i]
}
@Benchmark
fun nativeBufferRead() {
var res = 0
- for (i in 1..size) res += nativeBuffer.get(
- size - i
- )
+ for (i in 1..size) res += nativeBuffer[size - i]
}
companion object {
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index be52383ef..4d9ca1649 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/kmath-ast/README.md b/kmath-ast/README.md
index 043224800..19e9ee4a9 100644
--- a/kmath-ast/README.md
+++ b/kmath-ast/README.md
@@ -2,72 +2,85 @@
This subproject implements the following features:
-- Expression Language and its parser.
-- MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation.
-- Type-safe builder for MST.
-- Evaluating expressions by traversing MST.
+ - [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
+ - [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
+ - [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
+ - [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
+ - [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
+ - [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
+
> #### Artifact:
-> This module is distributed in the artifact `kscience.kmath:kmath-ast:0.1.4-dev-8`.
->
+>
+> This module artifact: `kscience.kmath:kmath-ast:0.2.0-dev-4`.
+>
+> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
+>
+> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-ast/_latestVersion)
+>
> **Gradle:**
>
> ```gradle
> repositories {
+> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
> maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
> maven { url 'https://dl.bintray.com/mipt-npm/dev' }
-> maven { url https://dl.bintray.com/hotkeytlt/maven' }
+> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
+>
> }
>
> dependencies {
-> implementation 'kscience.kmath:kmath-ast:0.1.4-dev-8'
+> implementation 'kscience.kmath:kmath-ast:0.2.0-dev-4'
> }
> ```
> **Gradle Kotlin DSL:**
>
> ```kotlin
> repositories {
+> maven("https://dl.bintray.com/kotlin/kotlin-eap")
> maven("https://dl.bintray.com/mipt-npm/kscience")
> maven("https://dl.bintray.com/mipt-npm/dev")
> maven("https://dl.bintray.com/hotkeytlt/maven")
> }
>
> dependencies {
-> implementation("kscience.kmath:kmath-ast:0.1.4-dev-8")
+> implementation("kscience.kmath:kmath-ast:0.2.0-dev-4")
> }
> ```
->
-## Dynamic Expression Code Generation with ObjectWeb ASM
+## Dynamic expression code generation
-`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds
-a special implementation of `Expression` with implemented `invoke` function.
+### On JVM
-For example, the following builder:
+`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds
+a special implementation of `Expression` with implemented `invoke` function.
+
+For example, the following builder:
```kotlin
RealField.mstInField { symbol("x") + 2 }.compile()
```
-… leads to generation of bytecode, which can be decompiled to the following Java class:
+… leads to generation of bytecode, which can be decompiled to the following Java class:
```java
package kscience.kmath.asm.generated;
import java.util.Map;
+import kotlin.jvm.functions.Function2;
import kscience.kmath.asm.internal.MapIntrinsics;
import kscience.kmath.expressions.Expression;
-import kscience.kmath.operations.RealField;
+import kscience.kmath.expressions.Symbol;
-public final class AsmCompiledExpression_1073786867_0 implements Expression {
- private final RealField algebra;
+public final class AsmCompiledExpression_45045_0 implements Expression {
+ private final Object[] constants;
- public final Double invoke(Map arguments) {
- return (Double)this.algebra.add(((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(), 2.0D);
+ public final Double invoke(Map arguments) {
+ return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2);
}
- public AsmCompiledExpression_1073786867_0(RealField algebra) {
- this.algebra = algebra;
+ public AsmCompiledExpression_45045_0(Object[] constants) {
+ this.constants = constants;
}
}
@@ -75,17 +88,35 @@ public final class AsmCompiledExpression_1073786867_0 implements Expression` with implemented `invoke` function.
+
+For example, the following builder:
+
+```kotlin
+RealField.mstInField { symbol("x") + 2 }.compile()
+```
+
+… leads to generation of bytecode, which can be decompiled to the following Java class:
+
+```java
+package kscience.kmath.asm.generated;
+
+import java.util.Map;
+import kotlin.jvm.functions.Function2;
+import kscience.kmath.asm.internal.MapIntrinsics;
+import kscience.kmath.expressions.Expression;
+import kscience.kmath.expressions.Symbol;
+
+public final class AsmCompiledExpression_45045_0 implements Expression {
+ private final Object[] constants;
+
+ public final Double invoke(Map arguments) {
+ return (Double)((Function2)this.constants[0]).invoke((Double)MapIntrinsics.getOrFail(arguments, "x"), 2);
+ }
+
+ public AsmCompiledExpression_45045_0(Object[] constants) {
+ this.constants = constants;
+ }
+}
+
+```
+
+### Example Usage
+
+This API extends MST and MstExpression, so you may optimize as both of them:
+
+```kotlin
+RealField.mstInField { symbol("x") + 2 }.compile()
+RealField.expression("x+2".parseMath())
+```
+
+#### Known issues
+
+- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
+ class loading overhead.
+- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders.
+
+### On JS
+
+A similar feature is also available on JS.
+
+```kotlin
+RealField.mstInField { symbol("x") + 2 }.compile()
+```
+
+The code above returns expression implemented with such a JS function:
+
+```js
+var executable = function (constants, arguments) {
+ return constants[1](constants[0](arguments, "x"), 2);
+};
+```
+
+#### Known issues
+
+- This feature uses `eval` which can be unavailable in several environments.
diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt
index f312323b9..6cf746722 100644
--- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt
+++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt
@@ -55,24 +55,24 @@ public sealed class MST {
public fun Algebra.evaluate(node: MST): T = when (node) {
is MST.Numeric -> (this as? NumericAlgebra)?.number(node.value)
?: error("Numeric nodes are not supported by $this")
+
is MST.Symbolic -> symbol(node.value)
- is MST.Unary -> unaryOperation(node.operation, evaluate(node.value))
+ is MST.Unary -> unaryOperationFunction(node.operation)(evaluate(node.value))
+
is MST.Binary -> when {
- this !is NumericAlgebra -> binaryOperation(node.operation, evaluate(node.left), evaluate(node.right))
+ this !is NumericAlgebra -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right))
node.left is MST.Numeric && node.right is MST.Numeric -> {
- val number = RealField.binaryOperation(
- node.operation,
- node.left.value.toDouble(),
- node.right.value.toDouble()
- )
+ val number = RealField
+ .binaryOperationFunction(node.operation)
+ .invoke(node.left.value.toDouble(), node.right.value.toDouble())
number(number)
}
- node.left is MST.Numeric -> leftSideNumberOperation(node.operation, node.left.value, evaluate(node.right))
- node.right is MST.Numeric -> rightSideNumberOperation(node.operation, evaluate(node.left), node.right.value)
- else -> binaryOperation(node.operation, evaluate(node.left), evaluate(node.right))
+ node.left is MST.Numeric -> leftSideNumberOperationFunction(node.operation)(node.left.value, evaluate(node.right))
+ node.right is MST.Numeric -> rightSideNumberOperationFunction(node.operation)(evaluate(node.left), node.right.value)
+ else -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right))
}
}
diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt
index 6ee6ab9af..80b164a7c 100644
--- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt
+++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt
@@ -6,53 +6,64 @@ import kscience.kmath.operations.*
* [Algebra] over [MST] nodes.
*/
public object MstAlgebra : NumericAlgebra {
- override fun number(value: Number): MST.Numeric = MST.Numeric(value)
+ public override fun number(value: Number): MST.Numeric = MST.Numeric(value)
+ public override fun symbol(value: String): MST.Symbolic = MST.Symbolic(value)
- override fun symbol(value: String): MST.Symbolic = MST.Symbolic(value)
+ public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary =
+ { arg -> MST.Unary(operation, arg) }
- override fun unaryOperation(operation: String, arg: MST): MST.Unary =
- MST.Unary(operation, arg)
-
- override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
- MST.Binary(operation, left, right)
+ public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary =
+ { left, right -> MST.Binary(operation, left, right) }
}
/**
* [Space] over [MST] nodes.
*/
public object MstSpace : Space, NumericAlgebra {
- override val zero: MST.Numeric by lazy { number(0.0) }
+ public override val zero: MST.Numeric by lazy { number(0.0) }
- override fun number(value: Number): MST.Numeric = MstAlgebra.number(value)
- override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value)
- override fun add(a: MST, b: MST): MST.Binary = binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
- override fun multiply(a: MST, k: Number): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION, a, number(k))
+ public override fun number(value: Number): MST.Numeric = MstAlgebra.number(value)
+ public override fun symbol(value: String): MST.Symbolic = MstAlgebra.symbol(value)
+ public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b)
+ public override operator fun MST.unaryPlus(): MST.Unary = unaryOperationFunction(SpaceOperations.PLUS_OPERATION)(this)
+ public override operator fun MST.unaryMinus(): MST.Unary = unaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this)
- override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
- MstAlgebra.binaryOperation(operation, left, right)
+ public override operator fun MST.minus(b: MST): MST.Binary =
+ binaryOperationFunction(SpaceOperations.MINUS_OPERATION)(this, b)
- override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstAlgebra.unaryOperation(operation, arg)
+ public override fun multiply(a: MST, k: Number): MST.Binary =
+ binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(k))
+
+ public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary =
+ MstAlgebra.binaryOperationFunction(operation)
+
+ public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary =
+ MstAlgebra.unaryOperationFunction(operation)
}
/**
* [Ring] over [MST] nodes.
*/
public object MstRing : Ring, NumericAlgebra {
- override val zero: MST.Numeric
+ public override val zero: MST.Numeric
get() = MstSpace.zero
- override val one: MST.Numeric by lazy { number(1.0) }
+ public override val one: MST.Numeric by lazy { number(1.0) }
- override fun number(value: Number): MST.Numeric = MstSpace.number(value)
- override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value)
- override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b)
- override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k)
- override fun multiply(a: MST, b: MST): MST.Binary = binaryOperation(RingOperations.TIMES_OPERATION, a, b)
+ public override fun number(value: Number): MST.Numeric = MstSpace.number(value)
+ public override fun symbol(value: String): MST.Symbolic = MstSpace.symbol(value)
+ public override fun add(a: MST, b: MST): MST.Binary = MstSpace.add(a, b)
+ public override fun multiply(a: MST, k: Number): MST.Binary = MstSpace.multiply(a, k)
+ public override fun multiply(a: MST, b: MST): MST.Binary = binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b)
+ public override operator fun MST.unaryPlus(): MST.Unary = MstSpace { +this@unaryPlus }
+ public override operator fun MST.unaryMinus(): MST.Unary = MstSpace { -this@unaryMinus }
+ public override operator fun MST.minus(b: MST): MST.Binary = MstSpace { this@minus - b }
- override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
- MstSpace.binaryOperation(operation, left, right)
+ public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary =
+ MstSpace.binaryOperationFunction(operation)
- override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstSpace.unaryOperation(operation, arg)
+ public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary =
+ MstAlgebra.unaryOperationFunction(operation)
}
/**
@@ -70,51 +81,56 @@ public object MstField : Field {
public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b)
public override fun multiply(a: MST, k: Number): MST.Binary = MstRing.multiply(a, k)
public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b)
- public override fun divide(a: MST, b: MST): MST.Binary = binaryOperation(FieldOperations.DIV_OPERATION, a, b)
+ public override fun divide(a: MST, b: MST): MST.Binary = binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b)
+ public override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus }
+ public override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus }
+ public override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b }
- public override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
- MstRing.binaryOperation(operation, left, right)
+ public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary =
+ MstRing.binaryOperationFunction(operation)
- override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstRing.unaryOperation(operation, arg)
+ public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstRing.unaryOperationFunction(operation)
}
/**
* [ExtendedField] over [MST] nodes.
*/
public object MstExtendedField : ExtendedField {
- override val zero: MST.Numeric
+ public override val zero: MST.Numeric
get() = MstField.zero
- override val one: MST.Numeric
+ public override val one: MST.Numeric
get() = MstField.one
- override fun symbol(value: String): MST.Symbolic = MstField.symbol(value)
- override fun number(value: Number): MST.Numeric = MstField.number(value)
- override fun sin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg)
- override fun cos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.COS_OPERATION, arg)
- override fun tan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.TAN_OPERATION, arg)
- override fun asin(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ASIN_OPERATION, arg)
- override fun acos(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ACOS_OPERATION, arg)
- override fun atan(arg: MST): MST.Unary = unaryOperation(TrigonometricOperations.ATAN_OPERATION, arg)
- override fun sinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.SINH_OPERATION, arg)
- override fun cosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.COSH_OPERATION, arg)
- override fun tanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.TANH_OPERATION, arg)
- override fun asinh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ASINH_OPERATION, arg)
- override fun acosh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ACOSH_OPERATION, arg)
- override fun atanh(arg: MST): MST.Unary = unaryOperation(HyperbolicOperations.ATANH_OPERATION, arg)
- override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b)
- override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k)
- override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b)
- override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b)
+ public override fun symbol(value: String): MST.Symbolic = MstField.symbol(value)
+ public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg)
+ public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg)
+ public override fun tan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.TAN_OPERATION)(arg)
+ public override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg)
+ public override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg)
+ public override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg)
+ public override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.SINH_OPERATION)(arg)
+ public override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.COSH_OPERATION)(arg)
+ public override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.TANH_OPERATION)(arg)
+ public override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ASINH_OPERATION)(arg)
+ public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ACOSH_OPERATION)(arg)
+ public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(HyperbolicOperations.ATANH_OPERATION)(arg)
+ public override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b)
+ public override fun multiply(a: MST, k: Number): MST.Binary = MstField.multiply(a, k)
+ public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b)
+ public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b)
+ public override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus }
+ public override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus }
+ public override operator fun MST.minus(b: MST): MST.Binary = MstField { this@minus - b }
- override fun power(arg: MST, pow: Number): MST.Binary =
- binaryOperation(PowerOperations.POW_OPERATION, arg, number(pow))
+ public override fun power(arg: MST, pow: Number): MST.Binary =
+ binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow))
- override fun exp(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.EXP_OPERATION, arg)
- override fun ln(arg: MST): MST.Unary = unaryOperation(ExponentialOperations.LN_OPERATION, arg)
+ public override fun exp(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg)
+ public override fun ln(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg)
- override fun binaryOperation(operation: String, left: MST, right: MST): MST.Binary =
- MstField.binaryOperation(operation, left, right)
+ public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary =
+ MstField.binaryOperationFunction(operation)
- override fun unaryOperation(operation: String, arg: MST): MST.Unary = MstField.unaryOperation(operation, arg)
+ public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstField.unaryOperationFunction(operation)
}
diff --git a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt
index f68e3f5f8..03d33aa2b 100644
--- a/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt
+++ b/kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstExpression.kt
@@ -15,11 +15,14 @@ import kotlin.contracts.contract
*/
public class MstExpression>(public val algebra: A, public val mst: MST) : Expression {
private inner class InnerAlgebra(val arguments: Map) : NumericAlgebra {
- override fun symbol(value: String): T = arguments[StringSymbol(value)] ?: algebra.symbol(value)
- override fun unaryOperation(operation: String, arg: T): T = algebra.unaryOperation(operation, arg)
+ override fun symbol(value: String): T = try {
+ algebra.symbol(value)
+ } catch (ignored: IllegalStateException) {
+ null
+ } ?: arguments.getValue(StringSymbol(value))
- override fun binaryOperation(operation: String, left: T, right: T): T =
- algebra.binaryOperation(operation, left, right)
+ override fun unaryOperationFunction(operation: String): (arg: T) -> T = algebra.unaryOperationFunction(operation)
+ override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = algebra.binaryOperationFunction(operation)
@Suppress("UNCHECKED_CAST")
override fun number(value: Number): T = if (algebra is NumericAlgebra<*>)
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt
new file mode 100644
index 000000000..159c5d5ec
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt
@@ -0,0 +1,78 @@
+package kscience.kmath.estree
+
+import kscience.kmath.ast.MST
+import kscience.kmath.ast.MstExpression
+import kscience.kmath.estree.internal.ESTreeBuilder
+import kscience.kmath.estree.internal.estree.BaseExpression
+import kscience.kmath.expressions.Expression
+import kscience.kmath.operations.Algebra
+import kscience.kmath.operations.NumericAlgebra
+import kscience.kmath.operations.RealField
+
+@PublishedApi
+internal fun MST.compileWith(algebra: Algebra): Expression {
+ fun ESTreeBuilder.visit(node: MST): BaseExpression = when (node) {
+ is MST.Symbolic -> {
+ val symbol = try {
+ algebra.symbol(node.value)
+ } catch (ignored: IllegalStateException) {
+ null
+ }
+
+ if (symbol != null)
+ constant(symbol)
+ else
+ variable(node.value)
+ }
+
+ is MST.Numeric -> constant(node.value)
+ is MST.Unary -> call(algebra.unaryOperationFunction(node.operation), visit(node.value))
+
+ is MST.Binary -> when {
+ algebra is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> constant(
+ algebra.number(
+ RealField
+ .binaryOperationFunction(node.operation)
+ .invoke(node.left.value.toDouble(), node.right.value.toDouble())
+ )
+ )
+
+ algebra is NumericAlgebra && node.left is MST.Numeric -> call(
+ algebra.leftSideNumberOperationFunction(node.operation),
+ visit(node.left),
+ visit(node.right),
+ )
+
+ algebra is NumericAlgebra && node.right is MST.Numeric -> call(
+ algebra.rightSideNumberOperationFunction(node.operation),
+ visit(node.left),
+ visit(node.right),
+ )
+
+ else -> call(
+ algebra.binaryOperationFunction(node.operation),
+ visit(node.left),
+ visit(node.right),
+ )
+ }
+ }
+
+ return ESTreeBuilder { visit(this@compileWith) }.instance
+}
+
+
+/**
+ * Compiles an [MST] to ESTree generated expression using given algebra.
+ *
+ * @author Alexander Nozik.
+ */
+public fun Algebra.expression(mst: MST): Expression =
+ mst.compileWith(this)
+
+/**
+ * Optimizes performance of an [MstExpression] by compiling it into ESTree generated expression.
+ *
+ * @author Alexander Nozik.
+ */
+public fun MstExpression>.compile(): Expression =
+ mst.compileWith(algebra)
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt
new file mode 100644
index 000000000..e1823813a
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/ESTreeBuilder.kt
@@ -0,0 +1,79 @@
+package kscience.kmath.estree.internal
+
+import kscience.kmath.estree.internal.astring.generate
+import kscience.kmath.estree.internal.estree.*
+import kscience.kmath.expressions.Expression
+import kscience.kmath.expressions.Symbol
+
+internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExpression) {
+ private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression {
+ @Suppress("UNUSED_VARIABLE")
+ override fun invoke(arguments: Map): T {
+ val e = executable
+ val c = constants
+ val a = js("{}")
+ arguments.forEach { (key, value) -> a[key.identity] = value }
+ return js("e(c, a)").unsafeCast()
+ }
+ }
+
+ val instance: Expression by lazy {
+ val node = Program(
+ sourceType = "script",
+ VariableDeclaration(
+ kind = "var",
+ VariableDeclarator(
+ id = Identifier("executable"),
+ init = FunctionExpression(
+ params = arrayOf(Identifier("constants"), Identifier("arguments")),
+ body = BlockStatement(ReturnStatement(bodyCallback())),
+ ),
+ ),
+ ),
+ )
+
+ eval(generate(node))
+ GeneratedExpression(js("executable"), constants.toTypedArray())
+ }
+
+ private val constants = mutableListOf()
+
+ fun constant(value: Any?) = when {
+ value == null || jsTypeOf(value) == "number" || jsTypeOf(value) == "string" || jsTypeOf(value) == "boolean" ->
+ SimpleLiteral(value)
+
+ jsTypeOf(value) == "undefined" -> Identifier("undefined")
+
+ else -> {
+ val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex
+
+ MemberExpression(
+ computed = true,
+ optional = false,
+ `object` = Identifier("constants"),
+ property = SimpleLiteral(idx),
+ )
+ }
+ }
+
+ fun variable(name: String): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name))
+
+ fun call(function: Function, vararg args: BaseExpression): BaseExpression = SimpleCallExpression(
+ optional = false,
+ callee = constant(function),
+ *args,
+ )
+
+ private companion object {
+ @Suppress("UNUSED_VARIABLE")
+ val getOrFail: (`object`: dynamic, key: String) -> dynamic = { `object`, key ->
+ val k = key
+ val o = `object`
+
+ if (!(js("k in o") as Boolean))
+ throw NoSuchElementException("Key $key is missing in the map.")
+
+ js("o[k]")
+ }
+ }
+}
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt
new file mode 100644
index 000000000..cf0a8de25
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.kt
@@ -0,0 +1,33 @@
+@file:JsModule("astring")
+@file:JsNonModule
+
+package kscience.kmath.estree.internal.astring
+
+import kscience.kmath.estree.internal.estree.BaseNode
+
+internal external interface Options {
+ var indent: String?
+ get() = definedExternally
+ set(value) = definedExternally
+ var lineEnd: String?
+ get() = definedExternally
+ set(value) = definedExternally
+ var startingIndentLevel: Number?
+ get() = definedExternally
+ set(value) = definedExternally
+ var comments: Boolean?
+ get() = definedExternally
+ set(value) = definedExternally
+ var generator: Any?
+ get() = definedExternally
+ set(value) = definedExternally
+ var sourceMap: Any?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external fun generate(node: BaseNode, options: Options /* Options & `T$0` */ = definedExternally): String
+
+internal external fun generate(node: BaseNode): String
+
+internal external var baseGenerator: Generator
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.typealises.kt
new file mode 100644
index 000000000..5a7fe4f16
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/astring/astring.typealises.kt
@@ -0,0 +1,3 @@
+package kscience.kmath.estree.internal.astring
+
+internal typealias Generator = Any
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/emitter/emitter.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/emitter/emitter.kt
new file mode 100644
index 000000000..1e0a95a16
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/emitter/emitter.kt
@@ -0,0 +1,13 @@
+package kscience.kmath.estree.internal.emitter
+
+internal open external class Emitter {
+ constructor(obj: Any)
+ constructor()
+
+ open fun on(event: String, fn: () -> Unit)
+ open fun off(event: String, fn: () -> Unit)
+ open fun once(event: String, fn: () -> Unit)
+ open fun emit(event: String, vararg any: Any)
+ open fun listeners(event: String): Array<() -> Unit>
+ open fun hasListeners(event: String): Boolean
+}
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt
new file mode 100644
index 000000000..5bc197d0c
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.extensions.kt
@@ -0,0 +1,62 @@
+package kscience.kmath.estree.internal.estree
+
+internal fun Program(sourceType: String, vararg body: dynamic) = object : Program {
+ override var type = "Program"
+ override var sourceType = sourceType
+ override var body = body
+}
+
+internal fun VariableDeclaration(kind: String, vararg declarations: VariableDeclarator) = object : VariableDeclaration {
+ override var type = "VariableDeclaration"
+ override var declarations = declarations.toList().toTypedArray()
+ override var kind = kind
+}
+
+internal fun VariableDeclarator(id: dynamic, init: dynamic) = object : VariableDeclarator {
+ override var type = "VariableDeclarator"
+ override var id = id
+ override var init = init
+}
+
+internal fun Identifier(name: String) = object : Identifier {
+ override var type = "Identifier"
+ override var name = name
+}
+
+internal fun FunctionExpression(params: Array, body: BlockStatement) = object : FunctionExpression {
+ override var params = params
+ override var type = "FunctionExpression"
+ override var body = body
+}
+
+internal fun BlockStatement(vararg body: dynamic) = object : BlockStatement {
+ override var type = "BlockStatement"
+ override var body = body
+}
+
+internal fun ReturnStatement(argument: dynamic) = object : ReturnStatement {
+ override var type = "ReturnStatement"
+ override var argument = argument
+}
+
+internal fun SimpleLiteral(value: dynamic) = object : SimpleLiteral {
+ override var type = "Literal"
+ override var value = value
+}
+
+internal fun MemberExpression(computed: Boolean, optional: Boolean, `object`: dynamic, property: dynamic) =
+ object : MemberExpression {
+ override var type = "MemberExpression"
+ override var computed = computed
+ override var optional = optional
+ override var `object` = `object`
+ override var property = property
+ }
+
+internal fun SimpleCallExpression(optional: Boolean, callee: dynamic, vararg arguments: dynamic) =
+ object : SimpleCallExpression {
+ override var type = "CallExpression"
+ override var optional = optional
+ override var callee = callee
+ override var arguments = arguments
+ }
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt
new file mode 100644
index 000000000..a5385d1ee
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/estree/estree.kt
@@ -0,0 +1,644 @@
+package kscience.kmath.estree.internal.estree
+
+import kotlin.js.RegExp
+
+internal external interface BaseNodeWithoutComments {
+ var type: String
+ var loc: SourceLocation?
+ get() = definedExternally
+ set(value) = definedExternally
+ var range: dynamic /* JsTuple */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface BaseNode : BaseNodeWithoutComments {
+ var leadingComments: Array?
+ get() = definedExternally
+ set(value) = definedExternally
+ var trailingComments: Array?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface Comment : BaseNodeWithoutComments {
+ override var type: String /* "Line" | "Block" */
+ var value: String
+}
+
+internal external interface SourceLocation {
+ var source: String?
+ get() = definedExternally
+ set(value) = definedExternally
+ var start: Position
+ var end: Position
+}
+
+internal external interface Position {
+ var line: Number
+ var column: Number
+}
+
+internal external interface Program : BaseNode {
+ override var type: String /* "Program" */
+ var sourceType: String /* "script" | "module" */
+ var body: Array
+ var comments: Array?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface Directive : BaseNode {
+ override var type: String /* "ExpressionStatement" */
+ var expression: dynamic /* SimpleLiteral | RegExpLiteral */
+ get() = definedExternally
+ set(value) = definedExternally
+ var directive: String
+}
+
+internal external interface BaseFunction : BaseNode {
+ var params: Array
+ var generator: Boolean?
+ get() = definedExternally
+ set(value) = definedExternally
+ var async: Boolean?
+ get() = definedExternally
+ set(value) = definedExternally
+ var body: dynamic /* BlockStatement | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface BaseStatement : BaseNode
+
+internal external interface EmptyStatement : BaseStatement {
+ override var type: String /* "EmptyStatement" */
+}
+
+internal external interface BlockStatement : BaseStatement {
+ override var type: String /* "BlockStatement" */
+ var body: Array
+ var innerComments: Array?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ExpressionStatement : BaseStatement {
+ override var type: String /* "ExpressionStatement" */
+ var expression: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface IfStatement : BaseStatement {
+ override var type: String /* "IfStatement" */
+ var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var consequent: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */
+ get() = definedExternally
+ set(value) = definedExternally
+ var alternate: dynamic /* ExpressionStatement? | BlockStatement? | EmptyStatement? | DebuggerStatement? | WithStatement? | ReturnStatement? | LabeledStatement? | BreakStatement? | ContinueStatement? | IfStatement? | SwitchStatement? | ThrowStatement? | TryStatement? | WhileStatement? | DoWhileStatement? | ForStatement? | ForInStatement? | ForOfStatement? | FunctionDeclaration? | VariableDeclaration? | ClassDeclaration? */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface LabeledStatement : BaseStatement {
+ override var type: String /* "LabeledStatement" */
+ var label: Identifier
+ var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface BreakStatement : BaseStatement {
+ override var type: String /* "BreakStatement" */
+ var label: Identifier?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ContinueStatement : BaseStatement {
+ override var type: String /* "ContinueStatement" */
+ var label: Identifier?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface WithStatement : BaseStatement {
+ override var type: String /* "WithStatement" */
+ var `object`: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface SwitchStatement : BaseStatement {
+ override var type: String /* "SwitchStatement" */
+ var discriminant: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var cases: Array
+}
+
+internal external interface ReturnStatement : BaseStatement {
+ override var type: String /* "ReturnStatement" */
+ var argument: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ThrowStatement : BaseStatement {
+ override var type: String /* "ThrowStatement" */
+ var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface TryStatement : BaseStatement {
+ override var type: String /* "TryStatement" */
+ var block: BlockStatement
+ var handler: CatchClause?
+ get() = definedExternally
+ set(value) = definedExternally
+ var finalizer: BlockStatement?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface WhileStatement : BaseStatement {
+ override var type: String /* "WhileStatement" */
+ var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface DoWhileStatement : BaseStatement {
+ override var type: String /* "DoWhileStatement" */
+ var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */
+ get() = definedExternally
+ set(value) = definedExternally
+ var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ForStatement : BaseStatement {
+ override var type: String /* "ForStatement" */
+ var init: dynamic /* VariableDeclaration? | ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */
+ get() = definedExternally
+ set(value) = definedExternally
+ var test: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */
+ get() = definedExternally
+ set(value) = definedExternally
+ var update: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */
+ get() = definedExternally
+ set(value) = definedExternally
+ var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface BaseForXStatement : BaseStatement {
+ var left: dynamic /* VariableDeclaration | Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ForInStatement : BaseForXStatement {
+ override var type: String /* "ForInStatement" */
+}
+
+internal external interface DebuggerStatement : BaseStatement {
+ override var type: String /* "DebuggerStatement" */
+}
+
+internal external interface BaseDeclaration : BaseStatement
+
+internal external interface FunctionDeclaration : BaseFunction, BaseDeclaration {
+ override var type: String /* "FunctionDeclaration" */
+ var id: Identifier?
+ override var body: BlockStatement
+}
+
+internal external interface VariableDeclaration : BaseDeclaration {
+ override var type: String /* "VariableDeclaration" */
+ var declarations: Array
+ var kind: String /* "var" | "let" | "const" */
+}
+
+internal external interface VariableDeclarator : BaseNode {
+ override var type: String /* "VariableDeclarator" */
+ var id: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var init: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface BaseExpression : BaseNode
+
+internal external interface ChainExpression : BaseExpression {
+ override var type: String /* "ChainExpression" */
+ var expression: dynamic /* SimpleCallExpression | MemberExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ThisExpression : BaseExpression {
+ override var type: String /* "ThisExpression" */
+}
+
+internal external interface ArrayExpression : BaseExpression {
+ override var type: String /* "ArrayExpression" */
+ var elements: Array
+}
+
+internal external interface ObjectExpression : BaseExpression {
+ override var type: String /* "ObjectExpression" */
+ var properties: Array
+}
+
+internal external interface Property : BaseNode {
+ override var type: String /* "Property" */
+ var key: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var value: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern */
+ get() = definedExternally
+ set(value) = definedExternally
+ var kind: String /* "init" | "get" | "set" */
+ var method: Boolean
+ var shorthand: Boolean
+ var computed: Boolean
+}
+
+internal external interface FunctionExpression : BaseFunction, BaseExpression {
+ var id: Identifier?
+ get() = definedExternally
+ set(value) = definedExternally
+ override var type: String /* "FunctionExpression" */
+ override var body: BlockStatement
+}
+
+internal external interface SequenceExpression : BaseExpression {
+ override var type: String /* "SequenceExpression" */
+ var expressions: Array
+}
+
+internal external interface UnaryExpression : BaseExpression {
+ override var type: String /* "UnaryExpression" */
+ var operator: String /* "-" | "+" | "!" | "~" | "typeof" | "void" | "delete" */
+ var prefix: Boolean
+ var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface BinaryExpression : BaseExpression {
+ override var type: String /* "BinaryExpression" */
+ var operator: String /* "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "**" | "|" | "^" | "&" | "in" | "instanceof" */
+ var left: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface AssignmentExpression : BaseExpression {
+ override var type: String /* "AssignmentExpression" */
+ var operator: String /* "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "**=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=" */
+ var left: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface UpdateExpression : BaseExpression {
+ override var type: String /* "UpdateExpression" */
+ var operator: String /* "++" | "--" */
+ var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var prefix: Boolean
+}
+
+internal external interface LogicalExpression : BaseExpression {
+ override var type: String /* "LogicalExpression" */
+ var operator: String /* "||" | "&&" | "??" */
+ var left: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ConditionalExpression : BaseExpression {
+ override var type: String /* "ConditionalExpression" */
+ var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var alternate: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var consequent: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface BaseCallExpression : BaseExpression {
+ var callee: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | Super */
+ get() = definedExternally
+ set(value) = definedExternally
+ var arguments: Array
+}
+
+internal external interface SimpleCallExpression : BaseCallExpression {
+ override var type: String /* "CallExpression" */
+ var optional: Boolean
+}
+
+internal external interface NewExpression : BaseCallExpression {
+ override var type: String /* "NewExpression" */
+}
+
+internal external interface MemberExpression : BaseExpression, BasePattern {
+ override var type: String /* "MemberExpression" */
+ var `object`: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | Super */
+ get() = definedExternally
+ set(value) = definedExternally
+ var property: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var computed: Boolean
+ var optional: Boolean
+}
+
+internal external interface BasePattern : BaseNode
+
+internal external interface SwitchCase : BaseNode {
+ override var type: String /* "SwitchCase" */
+ var test: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */
+ get() = definedExternally
+ set(value) = definedExternally
+ var consequent: Array
+}
+
+internal external interface CatchClause : BaseNode {
+ override var type: String /* "CatchClause" */
+ var param: dynamic /* Identifier? | ObjectPattern? | ArrayPattern? | RestElement? | AssignmentPattern? | MemberExpression? */
+ get() = definedExternally
+ set(value) = definedExternally
+ var body: BlockStatement
+}
+
+internal external interface Identifier : BaseNode, BaseExpression, BasePattern {
+ override var type: String /* "Identifier" */
+ var name: String
+}
+
+internal external interface SimpleLiteral : BaseNode, BaseExpression {
+ override var type: String /* "Literal" */
+ var value: dynamic /* String? | Boolean? | Number? */
+ get() = definedExternally
+ set(value) = definedExternally
+ var raw: String?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface `T$1` {
+ var pattern: String
+ var flags: String
+}
+
+internal external interface RegExpLiteral : BaseNode, BaseExpression {
+ override var type: String /* "Literal" */
+ var value: RegExp?
+ get() = definedExternally
+ set(value) = definedExternally
+ var regex: `T$1`
+ var raw: String?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ForOfStatement : BaseForXStatement {
+ override var type: String /* "ForOfStatement" */
+ var await: Boolean
+}
+
+internal external interface Super : BaseNode {
+ override var type: String /* "Super" */
+}
+
+internal external interface SpreadElement : BaseNode {
+ override var type: String /* "SpreadElement" */
+ var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ArrowFunctionExpression : BaseExpression, BaseFunction {
+ override var type: String /* "ArrowFunctionExpression" */
+ var expression: Boolean
+ override var body: dynamic /* BlockStatement | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface YieldExpression : BaseExpression {
+ override var type: String /* "YieldExpression" */
+ var argument: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */
+ get() = definedExternally
+ set(value) = definedExternally
+ var delegate: Boolean
+}
+
+internal external interface TemplateLiteral : BaseExpression {
+ override var type: String /* "TemplateLiteral" */
+ var quasis: Array
+ var expressions: Array
+}
+
+internal external interface TaggedTemplateExpression : BaseExpression {
+ override var type: String /* "TaggedTemplateExpression" */
+ var tag: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var quasi: TemplateLiteral
+}
+
+internal external interface `T$2` {
+ var cooked: String
+ var raw: String
+}
+
+internal external interface TemplateElement : BaseNode {
+ override var type: String /* "TemplateElement" */
+ var tail: Boolean
+ var value: `T$2`
+}
+
+internal external interface AssignmentProperty : Property {
+ override var value: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ override var kind: String /* "init" */
+ override var method: Boolean
+}
+
+internal external interface ObjectPattern : BasePattern {
+ override var type: String /* "ObjectPattern" */
+ var properties: Array
+}
+
+internal external interface ArrayPattern : BasePattern {
+ override var type: String /* "ArrayPattern" */
+ var elements: Array
+}
+
+internal external interface RestElement : BasePattern {
+ override var type: String /* "RestElement" */
+ var argument: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface AssignmentPattern : BasePattern {
+ override var type: String /* "AssignmentPattern" */
+ var left: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface BaseClass : BaseNode {
+ var superClass: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */
+ get() = definedExternally
+ set(value) = definedExternally
+ var body: ClassBody
+}
+
+internal external interface ClassBody : BaseNode {
+ override var type: String /* "ClassBody" */
+ var body: Array
+}
+
+internal external interface MethodDefinition : BaseNode {
+ override var type: String /* "MethodDefinition" */
+ var key: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+ var value: FunctionExpression
+ var kind: String /* "constructor" | "method" | "get" | "set" */
+ var computed: Boolean
+ var static: Boolean
+}
+
+internal external interface ClassDeclaration : BaseClass, BaseDeclaration {
+ override var type: String /* "ClassDeclaration" */
+ var id: Identifier?
+}
+
+internal external interface ClassExpression : BaseClass, BaseExpression {
+ override var type: String /* "ClassExpression" */
+ var id: Identifier?
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface MetaProperty : BaseExpression {
+ override var type: String /* "MetaProperty" */
+ var meta: Identifier
+ var property: Identifier
+}
+
+internal external interface BaseModuleDeclaration : BaseNode
+
+internal external interface BaseModuleSpecifier : BaseNode {
+ var local: Identifier
+}
+
+internal external interface ImportDeclaration : BaseModuleDeclaration {
+ override var type: String /* "ImportDeclaration" */
+ var specifiers: Array
+ var source: dynamic /* SimpleLiteral | RegExpLiteral */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ImportSpecifier : BaseModuleSpecifier {
+ override var type: String /* "ImportSpecifier" */
+ var imported: Identifier
+}
+
+internal external interface ImportExpression : BaseExpression {
+ override var type: String /* "ImportExpression" */
+ var source: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ImportDefaultSpecifier : BaseModuleSpecifier {
+ override var type: String /* "ImportDefaultSpecifier" */
+}
+
+internal external interface ImportNamespaceSpecifier : BaseModuleSpecifier {
+ override var type: String /* "ImportNamespaceSpecifier" */
+}
+
+internal external interface ExportNamedDeclaration : BaseModuleDeclaration {
+ override var type: String /* "ExportNamedDeclaration" */
+ var declaration: dynamic /* FunctionDeclaration? | VariableDeclaration? | ClassDeclaration? */
+ get() = definedExternally
+ set(value) = definedExternally
+ var specifiers: Array
+ var source: dynamic /* SimpleLiteral? | RegExpLiteral? */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ExportSpecifier : BaseModuleSpecifier {
+ override var type: String /* "ExportSpecifier" */
+ var exported: Identifier
+}
+
+internal external interface ExportDefaultDeclaration : BaseModuleDeclaration {
+ override var type: String /* "ExportDefaultDeclaration" */
+ var declaration: dynamic /* FunctionDeclaration | VariableDeclaration | ClassDeclaration | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface ExportAllDeclaration : BaseModuleDeclaration {
+ override var type: String /* "ExportAllDeclaration" */
+ var source: dynamic /* SimpleLiteral | RegExpLiteral */
+ get() = definedExternally
+ set(value) = definedExternally
+}
+
+internal external interface AwaitExpression : BaseExpression {
+ override var type: String /* "AwaitExpression" */
+ var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */
+ get() = definedExternally
+ set(value) = definedExternally
+}
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/stream/stream.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/stream/stream.kt
new file mode 100644
index 000000000..b3c65a758
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/stream/stream.kt
@@ -0,0 +1,7 @@
+package kscience.kmath.estree.internal.stream
+
+import kscience.kmath.estree.internal.emitter.Emitter
+
+internal open external class Stream : Emitter {
+ open fun pipe(dest: Any, options: Any): Any
+}
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt
new file mode 100644
index 000000000..22d4dd8e0
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es2015.iterable.kt
@@ -0,0 +1,25 @@
+package kscience.kmath.estree.internal.tsstdlib
+
+internal external interface IteratorYieldResult {
+ var done: Boolean?
+ get() = definedExternally
+ set(value) = definedExternally
+ var value: TYield
+}
+
+internal external interface IteratorReturnResult {
+ var done: Boolean
+ var value: TReturn
+}
+
+internal external interface Iterator {
+ fun next(vararg args: Any /* JsTuple<> | JsTuple */): dynamic /* IteratorYieldResult | IteratorReturnResult */
+ val `return`: ((value: TReturn) -> dynamic)?
+ val `throw`: ((e: Any) -> dynamic)?
+}
+
+internal typealias Iterator__1 = Iterator
+
+internal external interface Iterable
+
+internal external interface IterableIterator : Iterator__1
diff --git a/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es5.kt b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es5.kt
new file mode 100644
index 000000000..70f6d9702
--- /dev/null
+++ b/kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/internal/tsstdlib/lib.es5.kt
@@ -0,0 +1,82 @@
+@file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION")
+
+package kscience.kmath.estree.internal.tsstdlib
+
+import kotlin.js.RegExp
+
+internal typealias RegExpMatchArray = Array
+
+internal typealias RegExpExecArray = Array
+
+internal external interface RegExpConstructor {
+ @nativeInvoke
+ operator fun invoke(pattern: RegExp, flags: String = definedExternally): RegExp
+
+ @nativeInvoke
+ operator fun invoke(pattern: RegExp): RegExp
+
+ @nativeInvoke
+ operator fun invoke(pattern: String, flags: String = definedExternally): RegExp
+
+ @nativeInvoke
+ operator fun invoke(pattern: String): RegExp
+ var prototype: RegExp
+ var `$1`: String
+ var `$2`: String
+ var `$3`: String
+ var `$4`: String
+ var `$5`: String
+ var `$6`: String
+ var `$7`: String
+ var `$8`: String
+ var `$9`: String
+ var lastMatch: String
+}
+
+internal external interface ConcatArray {
+ var length: Number
+
+ @nativeGetter
+ operator fun get(n: Number): T?
+
+ @nativeSetter
+ operator fun set(n: Number, value: T)
+ fun join(separator: String = definedExternally): String
+ fun slice(start: Number = definedExternally, end: Number = definedExternally): Array
+}
+
+internal external interface ArrayConstructor {
+ fun from(iterable: Iterable): Array
+ fun from(iterable: ArrayLike): Array
+ fun from(iterable: Iterable, mapfn: (v: T, k: Number) -> U, thisArg: Any = definedExternally): Array
+ fun from(iterable: Iterable, mapfn: (v: T, k: Number) -> U): Array
+ fun from(iterable: ArrayLike, mapfn: (v: T, k: Number) -> U, thisArg: Any = definedExternally): Array
+ fun from(iterable: ArrayLike, mapfn: (v: T, k: Number) -> U): Array
+ fun of(vararg items: T): Array
+
+ @nativeInvoke
+ operator fun invoke(arrayLength: Number = definedExternally): Array
+
+ @nativeInvoke
+ operator fun invoke(): Array
+
+ @nativeInvoke
+ operator fun invoke(arrayLength: Number): Array
+
+ @nativeInvoke
+ operator fun invoke(vararg items: T): Array
+ fun isArray(arg: Any): Boolean
+ var prototype: Array
+}
+
+internal external interface ArrayLike {
+ var length: Number
+
+ @nativeGetter
+ operator fun get(n: Number): T?
+
+ @nativeSetter
+ operator fun set(n: Number, value: T)
+}
+
+internal typealias Extract = Any
diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt
new file mode 100644
index 000000000..b9be02d49
--- /dev/null
+++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeConsistencyWithInterpreter.kt
@@ -0,0 +1,115 @@
+package kscience.kmath.estree
+
+import kscience.kmath.ast.*
+import kscience.kmath.expressions.invoke
+import kscience.kmath.operations.ByteRing
+import kscience.kmath.operations.ComplexField
+import kscience.kmath.operations.RealField
+import kscience.kmath.operations.toComplex
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+internal class TestESTreeConsistencyWithInterpreter {
+ @Test
+ fun mstSpace() {
+ val res1 = MstSpace.mstInSpace {
+ binaryOperationFunction("+")(
+ unaryOperationFunction("+")(
+ number(3.toByte()) - (number(2.toByte()) + (multiply(
+ add(number(1), number(1)),
+ 2
+ ) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
+ ),
+
+ number(1)
+ ) + symbol("x") + zero
+ }("x" to MST.Numeric(2))
+
+ val res2 = MstSpace.mstInSpace {
+ binaryOperationFunction("+")(
+ unaryOperationFunction("+")(
+ number(3.toByte()) - (number(2.toByte()) + (multiply(
+ add(number(1), number(1)),
+ 2
+ ) + number(1.toByte()) * 3.toByte() - number(1.toByte())))
+ ),
+
+ number(1)
+ ) + symbol("x") + zero
+ }.compile()("x" to MST.Numeric(2))
+
+ assertEquals(res1, res2)
+ }
+
+ @Test
+ fun byteRing() {
+ val res1 = ByteRing.mstInRing {
+ binaryOperationFunction("+")(
+ unaryOperationFunction("+")(
+ (symbol("x") - (2.toByte() + (multiply(
+ add(number(1), number(1)),
+ 2
+ ) + 1.toByte()))) * 3.0 - 1.toByte()
+ ),
+
+ number(1)
+ ) * number(2)
+ }("x" to 3.toByte())
+
+ val res2 = ByteRing.mstInRing {
+ binaryOperationFunction("+")(
+ unaryOperationFunction("+")(
+ (symbol("x") - (2.toByte() + (multiply(
+ add(number(1), number(1)),
+ 2
+ ) + 1.toByte()))) * 3.0 - 1.toByte()
+ ),
+ number(1)
+ ) * number(2)
+ }.compile()("x" to 3.toByte())
+
+ assertEquals(res1, res2)
+ }
+
+ @Test
+ fun realField() {
+ val res1 = RealField.mstInField {
+ +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
+ (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ + number(1),
+ number(1) / 2 + number(2.0) * one
+ ) + zero
+ }("x" to 2.0)
+
+ val res2 = RealField.mstInField {
+ +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
+ (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ + number(1),
+ number(1) / 2 + number(2.0) * one
+ ) + zero
+ }.compile()("x" to 2.0)
+
+ assertEquals(res1, res2)
+ }
+
+ @Test
+ fun complexField() {
+ val res1 = ComplexField.mstInField {
+ +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
+ (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ + number(1),
+ number(1) / 2 + number(2.0) * one
+ ) + zero
+ }("x" to 2.0.toComplex())
+
+ val res2 = ComplexField.mstInField {
+ +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
+ (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ + number(1),
+ number(1) / 2 + number(2.0) * one
+ ) + zero
+ }.compile()("x" to 2.0.toComplex())
+
+ assertEquals(res1, res2)
+ }
+}
diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeOperationsSupport.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeOperationsSupport.kt
new file mode 100644
index 000000000..72a4669d9
--- /dev/null
+++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeOperationsSupport.kt
@@ -0,0 +1,41 @@
+package kscience.kmath.estree
+
+import kscience.kmath.ast.mstInExtendedField
+import kscience.kmath.ast.mstInField
+import kscience.kmath.ast.mstInSpace
+import kscience.kmath.expressions.invoke
+import kscience.kmath.operations.RealField
+import kotlin.random.Random
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+internal class TestESTreeOperationsSupport {
+ @Test
+ fun testUnaryOperationInvocation() {
+ val expression = RealField.mstInSpace { -symbol("x") }.compile()
+ val res = expression("x" to 2.0)
+ assertEquals(-2.0, res)
+ }
+
+ @Test
+ fun testBinaryOperationInvocation() {
+ val expression = RealField.mstInSpace { -symbol("x") + number(1.0) }.compile()
+ val res = expression("x" to 2.0)
+ assertEquals(-1.0, res)
+ }
+
+ @Test
+ fun testConstProductInvocation() {
+ val res = RealField.mstInField { symbol("x") * 2 }("x" to 2.0)
+ assertEquals(4.0, res)
+ }
+
+ @Test
+ fun testMultipleCalls() {
+ val e = RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile()
+ val r = Random(0)
+ var s = 0.0
+ repeat(1000000) { s += e("x" to r.nextDouble()) }
+ println(s)
+ }
+}
diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt
new file mode 100644
index 000000000..9d0d17e58
--- /dev/null
+++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeSpecialization.kt
@@ -0,0 +1,54 @@
+package kscience.kmath.estree
+
+import kscience.kmath.ast.mstInField
+import kscience.kmath.expressions.invoke
+import kscience.kmath.operations.RealField
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+internal class TestESTreeSpecialization {
+ @Test
+ fun testUnaryPlus() {
+ val expr = RealField.mstInField { unaryOperationFunction("+")(symbol("x")) }.compile()
+ assertEquals(2.0, expr("x" to 2.0))
+ }
+
+ @Test
+ fun testUnaryMinus() {
+ val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile()
+ assertEquals(-2.0, expr("x" to 2.0))
+ }
+
+ @Test
+ fun testAdd() {
+ val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile()
+ assertEquals(4.0, expr("x" to 2.0))
+ }
+
+ @Test
+ fun testSine() {
+ val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile()
+ assertEquals(0.0, expr("x" to 0.0))
+ }
+
+ @Test
+ fun testMinus() {
+ val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile()
+ assertEquals(0.0, expr("x" to 2.0))
+ }
+
+ @Test
+ fun testDivide() {
+ val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile()
+ assertEquals(1.0, expr("x" to 2.0))
+ }
+
+ @Test
+ fun testPower() {
+ val expr = RealField
+ .mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) }
+ .compile()
+
+ assertEquals(4.0, expr("x" to 2.0))
+ }
+}
diff --git a/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt
new file mode 100644
index 000000000..846120ee2
--- /dev/null
+++ b/kmath-ast/src/jsTest/kotlin/kscience/kmath/estree/TestESTreeVariables.kt
@@ -0,0 +1,22 @@
+package kscience.kmath.estree
+
+import kscience.kmath.ast.mstInRing
+import kscience.kmath.expressions.invoke
+import kscience.kmath.operations.ByteRing
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+
+internal class TestESTreeVariables {
+ @Test
+ fun testVariable() {
+ val expr = ByteRing.mstInRing { symbol("x") }.compile()
+ assertEquals(1.toByte(), expr("x" to 1.toByte()))
+ }
+
+ @Test
+ fun testUndefinedVariableFails() {
+ val expr = ByteRing.mstInRing { symbol("x") }.compile()
+ assertFailsWith { expr() }
+ }
+}
diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt
index 9ccfa464c..b98c0bfce 100644
--- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt
+++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt
@@ -1,13 +1,13 @@
package kscience.kmath.asm
import kscience.kmath.asm.internal.AsmBuilder
-import kscience.kmath.asm.internal.MstType
-import kscience.kmath.asm.internal.buildAlgebraOperationCall
import kscience.kmath.asm.internal.buildName
import kscience.kmath.ast.MST
import kscience.kmath.ast.MstExpression
import kscience.kmath.expressions.Expression
import kscience.kmath.operations.Algebra
+import kscience.kmath.operations.NumericAlgebra
+import kscience.kmath.operations.RealField
/**
* Compiles given MST to an Expression using AST compiler.
@@ -23,37 +23,46 @@ internal fun MST.compileWith(type: Class, algebra: Algebra): Exp
is MST.Symbolic -> {
val symbol = try {
algebra.symbol(node.value)
- } catch (ignored: Throwable) {
+ } catch (ignored: IllegalStateException) {
null
}
if (symbol != null)
- loadTConstant(symbol)
+ loadObjectConstant(symbol as Any)
else
loadVariable(node.value)
}
- is MST.Numeric -> loadNumeric(node.value)
+ is MST.Numeric -> loadNumberConstant(node.value)
+ is MST.Unary -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) }
- is MST.Unary -> buildAlgebraOperationCall(
- context = algebra,
- name = node.operation,
- fallbackMethodName = "unaryOperation",
- parameterTypes = arrayOf(MstType.fromMst(node.value))
- ) { visit(node.value) }
+ is MST.Binary -> when {
+ algebra is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> loadObjectConstant(
+ algebra.number(
+ RealField
+ .binaryOperationFunction(node.operation)
+ .invoke(node.left.value.toDouble(), node.right.value.toDouble())
+ )
+ )
- is MST.Binary -> buildAlgebraOperationCall(
- context = algebra,
- name = node.operation,
- fallbackMethodName = "binaryOperation",
- parameterTypes = arrayOf(MstType.fromMst(node.left), MstType.fromMst(node.right))
- ) {
- visit(node.left)
- visit(node.right)
+ algebra is NumericAlgebra && node.left is MST.Numeric -> buildCall(algebra.leftSideNumberOperationFunction(node.operation)) {
+ visit(node.left)
+ visit(node.right)
+ }
+
+ algebra is NumericAlgebra && node.right is MST.Numeric -> buildCall(algebra.rightSideNumberOperationFunction(node.operation)) {
+ visit(node.left)
+ visit(node.right)
+ }
+
+ else -> buildCall(algebra.binaryOperationFunction(node.operation)) {
+ visit(node.left)
+ visit(node.right)
+ }
}
}
- return AsmBuilder(type, algebra, buildName(this)) { visit(this@compileWith) }.getInstance()
+ return AsmBuilder(type, buildName(this)) { visit(this@compileWith) }.instance
}
/**
diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt
index a1e482103..1edbed28d 100644
--- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt
+++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/AsmBuilder.kt
@@ -3,29 +3,30 @@ package kscience.kmath.asm.internal
import kscience.kmath.asm.internal.AsmBuilder.ClassLoader
import kscience.kmath.ast.MST
import kscience.kmath.expressions.Expression
-import kscience.kmath.operations.Algebra
-import kscience.kmath.operations.NumericAlgebra
import org.objectweb.asm.*
import org.objectweb.asm.Opcodes.*
+import org.objectweb.asm.Type.*
import org.objectweb.asm.commons.InstructionAdapter
-import java.util.*
-import java.util.stream.Collectors
+import java.lang.invoke.MethodHandles
+import java.lang.invoke.MethodType
+import java.lang.reflect.Modifier
+import java.util.stream.Collectors.toMap
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
/**
* ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression.
* This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class.
*
* @property T the type of AsmExpression to unwrap.
- * @property algebra the algebra the applied AsmExpressions use.
* @property className the unique class name of new loaded class.
- * @property invokeLabel0Visitor the function to apply to this object when generating invoke method, label 0.
+ * @property callbackAtInvokeL0 the function to apply to this object when generating invoke method, label 0.
* @author Iaroslav Postovalov
*/
-internal class AsmBuilder internal constructor(
- private val classOfT: Class<*>,
- private val algebra: Algebra,
+internal class AsmBuilder(
+ classOfT: Class<*>,
private val className: String,
- private val invokeLabel0Visitor: AsmBuilder.() -> Unit,
+ private val callbackAtInvokeL0: AsmBuilder.() -> Unit,
) {
/**
* Internal classloader of [AsmBuilder] with alias to define class from byte array.
@@ -39,20 +40,15 @@ internal class AsmBuilder internal constructor(
*/
private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader)
- /**
- * ASM Type for [algebra].
- */
- private val tAlgebraType: Type = algebra.javaClass.asm
-
/**
* ASM type for [T].
*/
- internal val tType: Type = classOfT.asm
+ private val tType: Type = classOfT.asm
/**
* ASM type for new class.
*/
- private val classType: Type = Type.getObjectType(className.replace(oldChar = '.', newChar = '/'))!!
+ private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/'))
/**
* List of constants to provide to the subclass.
@@ -64,55 +60,14 @@ internal class AsmBuilder internal constructor(
*/
private lateinit var invokeMethodVisitor: InstructionAdapter
- /**
- * States whether this [AsmBuilder] needs to generate constants field.
- */
- private var hasConstants: Boolean = true
-
- /**
- * States whether [T] a primitive type, so [AsmBuilder] may generate direct primitive calls.
- */
- internal var primitiveMode: Boolean = false
-
- /**
- * Primitive type to apply for specific primitive calls. Use [OBJECT_TYPE], if not in [primitiveMode].
- */
- internal var primitiveMask: Type = OBJECT_TYPE
-
- /**
- * Boxed primitive type to apply for specific primitive calls. Use [OBJECT_TYPE], if not in [primitiveMode].
- */
- internal var primitiveMaskBoxed: Type = OBJECT_TYPE
-
- /**
- * Stack of useful objects types on stack to verify types.
- */
- private val typeStack: ArrayDeque = ArrayDeque()
-
- /**
- * Stack of useful objects types on stack expected by algebra calls.
- */
- internal val expectationStack: ArrayDeque = ArrayDeque(1).also { it.push(tType) }
-
- /**
- * The cache for instance built by this builder.
- */
- private var generatedInstance: Expression? = null
-
/**
* Subclasses, loads and instantiates [Expression] for given parameters.
*
* The built instance is cached.
*/
@Suppress("UNCHECKED_CAST")
- internal fun getInstance(): Expression {
- generatedInstance?.let { return it }
-
- if (SIGNATURE_LETTERS.containsKey(classOfT)) {
- primitiveMode = true
- primitiveMask = SIGNATURE_LETTERS.getValue(classOfT)
- primitiveMaskBoxed = tType
- }
+ val instance: Expression by lazy {
+ val hasConstants: Boolean
val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) {
visit(
@@ -121,20 +76,20 @@ internal class AsmBuilder internal constructor(
classType.internalName,
"${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;",
OBJECT_TYPE.internalName,
- arrayOf(EXPRESSION_TYPE.internalName)
+ arrayOf(EXPRESSION_TYPE.internalName),
)
visitMethod(
ACC_PUBLIC or ACC_FINAL,
"invoke",
- Type.getMethodDescriptor(tType, MAP_TYPE),
- "(L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}",
- null
+ getMethodDescriptor(tType, MAP_TYPE),
+ "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}${if (Modifier.isFinal(classOfT.modifiers)) "" else "+"}${tType.descriptor}>;)${tType.descriptor}",
+ null,
).instructionAdapter {
invokeMethodVisitor = this
visitCode()
val l0 = label()
- invokeLabel0Visitor()
+ callbackAtInvokeL0()
areturn(tType)
val l1 = label()
@@ -144,7 +99,7 @@ internal class AsmBuilder internal constructor(
null,
l0,
l1,
- invokeThisVar
+ 0,
)
visitLocalVariable(
@@ -153,7 +108,7 @@ internal class AsmBuilder internal constructor(
"L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;",
l0,
l1,
- invokeArgumentsVar
+ 1,
)
visitMaxs(0, 2)
@@ -163,17 +118,15 @@ internal class AsmBuilder internal constructor(
visitMethod(
ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC,
"invoke",
- Type.getMethodDescriptor(OBJECT_TYPE, MAP_TYPE),
+ getMethodDescriptor(OBJECT_TYPE, MAP_TYPE),
+ null,
null,
- null
).instructionAdapter {
- val thisVar = 0
- val argumentsVar = 1
visitCode()
val l0 = label()
- load(thisVar, OBJECT_TYPE)
- load(argumentsVar, MAP_TYPE)
- invokevirtual(classType.internalName, "invoke", Type.getMethodDescriptor(tType, MAP_TYPE), false)
+ load(0, OBJECT_TYPE)
+ load(1, MAP_TYPE)
+ invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false)
areturn(tType)
val l1 = label()
@@ -183,7 +136,7 @@ internal class AsmBuilder internal constructor(
null,
l0,
l1,
- thisVar
+ 0,
)
visitMaxs(0, 2)
@@ -192,15 +145,6 @@ internal class AsmBuilder internal constructor(
hasConstants = constants.isNotEmpty()
- visitField(
- access = ACC_PRIVATE or ACC_FINAL,
- name = "algebra",
- descriptor = tAlgebraType.descriptor,
- signature = null,
- value = null,
- block = FieldVisitor::visitEnd
- )
-
if (hasConstants)
visitField(
access = ACC_PRIVATE or ACC_FINAL,
@@ -208,55 +152,36 @@ internal class AsmBuilder internal constructor(
descriptor = OBJECT_ARRAY_TYPE.descriptor,
signature = null,
value = null,
- block = FieldVisitor::visitEnd
+ block = FieldVisitor::visitEnd,
)
visitMethod(
ACC_PUBLIC,
"",
-
- Type.getMethodDescriptor(
- Type.VOID_TYPE,
- tAlgebraType,
- *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }),
-
+ getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }),
+ null,
null,
- null
).instructionAdapter {
- val thisVar = 0
- val algebraVar = 1
- val constantsVar = 2
val l0 = label()
- load(thisVar, classType)
- invokespecial(OBJECT_TYPE.internalName, "", Type.getMethodDescriptor(Type.VOID_TYPE), false)
+ load(0, classType)
+ invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false)
label()
- load(thisVar, classType)
- load(algebraVar, tAlgebraType)
- putfield(classType.internalName, "algebra", tAlgebraType.descriptor)
+ load(0, classType)
if (hasConstants) {
label()
- load(thisVar, classType)
- load(constantsVar, OBJECT_ARRAY_TYPE)
+ load(0, classType)
+ load(1, OBJECT_ARRAY_TYPE)
putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor)
}
label()
visitInsn(RETURN)
val l4 = label()
- visitLocalVariable("this", classType.descriptor, null, l0, l4, thisVar)
-
- visitLocalVariable(
- "algebra",
- tAlgebraType.descriptor,
- null,
- l0,
- l4,
- algebraVar
- )
+ visitLocalVariable("this", classType.descriptor, null, l0, l4, 0)
if (hasConstants)
- visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, constantsVar)
+ visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, 1)
visitMaxs(0, 3)
visitEnd()
@@ -265,296 +190,156 @@ internal class AsmBuilder internal constructor(
visitEnd()
}
- val new = classLoader
- .defineClass(className, classWriter.toByteArray())
- .constructors
- .first()
- .newInstance(algebra, *(constants.toTypedArray().wrapToArrayIf { hasConstants })) as Expression
+ val cls = classLoader.defineClass(className, classWriter.toByteArray())
+ java.io.File("dump.class").writeBytes(classWriter.toByteArray())
+ val l = MethodHandles.publicLookup()
- generatedInstance = new
- return new
+ if (hasConstants)
+ l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java))
+ .invoke(constants.toTypedArray()) as Expression
+ else
+ l.findConstructor(cls, MethodType.methodType(Void.TYPE)).invoke() as Expression
}
- /**
- * Loads a [T] constant from [constants].
- */
- internal fun loadTConstant(value: T) {
- if (classOfT in INLINABLE_NUMBERS) {
- val expectedType = expectationStack.pop()
- val mustBeBoxed = expectedType.sort == Type.OBJECT
- loadNumberConstant(value as Number, mustBeBoxed)
-
- if (mustBeBoxed)
- invokeMethodVisitor.checkcast(tType)
-
- if (mustBeBoxed) typeStack.push(tType) else typeStack.push(primitiveMask)
- return
- }
-
- loadObjectConstant(value as Any, tType)
- }
-
- /**
- * Boxes the current value and pushes it.
- */
- private fun box(primitive: Type) {
- val r = PRIMITIVES_TO_BOXED.getValue(primitive)
-
- invokeMethodVisitor.invokestatic(
- r.internalName,
- "valueOf",
- Type.getMethodDescriptor(r, primitive),
- false
- )
- }
-
- /**
- * Unboxes the current boxed value and pushes it.
- */
- private fun unboxTo(primitive: Type) = invokeMethodVisitor.invokevirtual(
- NUMBER_TYPE.internalName,
- NUMBER_CONVERTER_METHODS.getValue(primitive),
- Type.getMethodDescriptor(primitive),
- false
- )
-
/**
* Loads [java.lang.Object] constant from constants.
*/
- private fun loadObjectConstant(value: Any, type: Type): Unit = invokeMethodVisitor.run {
- val idx = if (value in constants) constants.indexOf(value) else constants.apply { add(value) }.lastIndex
- loadThis()
+ fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run {
+ val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex
+ invokeMethodVisitor.load(0, classType)
getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor)
iconst(idx)
visitInsn(AALOAD)
- checkcast(type)
+ if (type != OBJECT_TYPE) checkcast(type)
}
- internal fun loadNumeric(value: Number) {
- if (expectationStack.peek() == NUMBER_TYPE) {
- loadNumberConstant(value, true)
- expectationStack.pop()
- typeStack.push(NUMBER_TYPE)
- } else (algebra as? NumericAlgebra)?.number(value)?.let { loadTConstant(it) }
- ?: error("Cannot resolve numeric $value since target algebra is not numeric, and the current operation doesn't accept numbers.")
- }
-
- /**
- * Loads this variable.
- */
- private fun loadThis(): Unit = invokeMethodVisitor.load(invokeThisVar, classType)
-
/**
* Either loads a numeric constant [value] from the class's constants field or boxes a primitive
- * constant from the constant pool (some numbers with special opcodes like [Opcodes.ICONST_0] aren't even loaded
- * from it).
+ * constant from the constant pool.
*/
- private fun loadNumberConstant(value: Number, mustBeBoxed: Boolean) {
+ fun loadNumberConstant(value: Number) {
val boxed = value.javaClass.asm
val primitive = BOXED_TO_PRIMITIVES[boxed]
if (primitive != null) {
when (primitive) {
- Type.BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt())
- Type.DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble())
- Type.FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat())
- Type.LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong())
- Type.INT_TYPE -> invokeMethodVisitor.iconst(value.toInt())
- Type.SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt())
+ BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt())
+ DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble())
+ FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat())
+ LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong())
+ INT_TYPE -> invokeMethodVisitor.iconst(value.toInt())
+ SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt())
}
- if (mustBeBoxed)
- box(primitive)
+ val r = PRIMITIVES_TO_BOXED.getValue(primitive)
+
+ invokeMethodVisitor.invokestatic(
+ r.internalName,
+ "valueOf",
+ getMethodDescriptor(r, primitive),
+ false,
+ )
return
}
loadObjectConstant(value, boxed)
-
- if (!mustBeBoxed)
- unboxTo(primitiveMask)
}
/**
- * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The [defaultValue] may be
- * provided.
+ * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke].
*/
- internal fun loadVariable(name: String): Unit = invokeMethodVisitor.run {
- load(invokeArgumentsVar, MAP_TYPE)
+ fun loadVariable(name: String): Unit = invokeMethodVisitor.run {
+ load(1, MAP_TYPE)
aconst(name)
invokestatic(
MAP_INTRINSICS_TYPE.internalName,
"getOrFail",
- Type.getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE),
- false
+ getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE),
+ false,
)
checkcast(tType)
- val expectedType = expectationStack.pop()
-
- if (expectedType.sort == Type.OBJECT)
- typeStack.push(tType)
- else {
- unboxTo(primitiveMask)
- typeStack.push(primitiveMask)
- }
}
- /**
- * Loads algebra from according field of the class and casts it to class of [algebra] provided.
- */
- internal fun loadAlgebra() {
- loadThis()
- invokeMethodVisitor.getfield(classType.internalName, "algebra", tAlgebraType.descriptor)
- }
+ inline fun buildCall(function: Function, parameters: AsmBuilder.() -> Unit) {
+ contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) }
+ val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces }
- /**
- * Writes a method instruction of opcode with its [owner], [method] and its [descriptor]. The default opcode is
- * [Opcodes.INVOKEINTERFACE], since most Algebra functions are declared in interfaces. [loadAlgebra] should be
- * called before the arguments and this operation.
- *
- * The result is casted to [T] automatically.
- */
- internal fun invokeAlgebraOperation(
- owner: String,
- method: String,
- descriptor: String,
- expectedArity: Int,
- opcode: Int = INVOKEINTERFACE,
- ) {
- run loop@{
- repeat(expectedArity) {
- if (typeStack.isEmpty()) return@loop
- typeStack.pop()
- }
- }
+ val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount
+ ?: error("Provided function object doesn't contain invoke method")
- invokeMethodVisitor.visitMethodInsn(
- opcode,
- owner,
- method,
- descriptor,
- opcode == INVOKEINTERFACE
+ val type = getType(`interface`)
+ loadObjectConstant(function, type)
+ parameters(this)
+
+ invokeMethodVisitor.invokeinterface(
+ type.internalName,
+ "invoke",
+ getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE }),
)
invokeMethodVisitor.checkcast(tType)
- val isLastExpr = expectationStack.size == 1
- val expectedType = expectationStack.pop()
-
- if (expectedType.sort == Type.OBJECT || isLastExpr)
- typeStack.push(tType)
- else {
- unboxTo(primitiveMask)
- typeStack.push(primitiveMask)
- }
}
- /**
- * Writes a LDC Instruction with string constant provided.
- */
- internal fun loadStringConstant(string: String): Unit = invokeMethodVisitor.aconst(string)
-
- internal companion object {
- /**
- * Index of `this` variable in invoke method of the built subclass.
- */
- private const val invokeThisVar: Int = 0
-
- /**
- * Index of `arguments` variable in invoke method of the built subclass.
- */
- private const val invokeArgumentsVar: Int = 1
-
- /**
- * Maps JVM primitive numbers boxed types to their primitive ASM types.
- */
- private val SIGNATURE_LETTERS: Map, Type> by lazy {
- hashMapOf(
- java.lang.Byte::class.java to Type.BYTE_TYPE,
- java.lang.Short::class.java to Type.SHORT_TYPE,
- java.lang.Integer::class.java to Type.INT_TYPE,
- java.lang.Long::class.java to Type.LONG_TYPE,
- java.lang.Float::class.java to Type.FLOAT_TYPE,
- java.lang.Double::class.java to Type.DOUBLE_TYPE
- )
- }
-
+ companion object {
/**
* Maps JVM primitive numbers boxed ASM types to their primitive ASM types.
*/
- private val BOXED_TO_PRIMITIVES: Map by lazy { SIGNATURE_LETTERS.mapKeys { (k, _) -> k.asm } }
+ private val BOXED_TO_PRIMITIVES: Map by lazy {
+ hashMapOf(
+ Byte::class.java.asm to BYTE_TYPE,
+ Short::class.java.asm to SHORT_TYPE,
+ Integer::class.java.asm to INT_TYPE,
+ Long::class.java.asm to LONG_TYPE,
+ Float::class.java.asm to FLOAT_TYPE,
+ Double::class.java.asm to DOUBLE_TYPE,
+ )
+ }
/**
* Maps JVM primitive numbers boxed ASM types to their primitive ASM types.
*/
private val PRIMITIVES_TO_BOXED: Map by lazy {
BOXED_TO_PRIMITIVES.entries.stream().collect(
- Collectors.toMap(
- Map.Entry::value,
- Map.Entry::key
- )
+ toMap(Map.Entry::value, Map.Entry::key),
)
}
- /**
- * Maps primitive ASM types to [Number] functions unboxing them.
- */
- private val NUMBER_CONVERTER_METHODS: Map by lazy {
- hashMapOf(
- Type.BYTE_TYPE to "byteValue",
- Type.SHORT_TYPE to "shortValue",
- Type.INT_TYPE to "intValue",
- Type.LONG_TYPE to "longValue",
- Type.FLOAT_TYPE to "floatValue",
- Type.DOUBLE_TYPE to "doubleValue"
- )
- }
-
- /**
- * Provides boxed number types values of which can be stored in JVM bytecode constant pool.
- */
- private val INLINABLE_NUMBERS: Set> by lazy { SIGNATURE_LETTERS.keys }
-
/**
* ASM type for [Expression].
*/
- internal val EXPRESSION_TYPE: Type by lazy { Type.getObjectType("kscience/kmath/expressions/Expression") }
-
- /**
- * ASM type for [java.lang.Number].
- */
- internal val NUMBER_TYPE: Type by lazy { Type.getObjectType("java/lang/Number") }
+ val EXPRESSION_TYPE: Type by lazy { getObjectType("kscience/kmath/expressions/Expression") }
/**
* ASM type for [java.util.Map].
*/
- internal val MAP_TYPE: Type by lazy { Type.getObjectType("java/util/Map") }
+ val MAP_TYPE: Type by lazy { getObjectType("java/util/Map") }
/**
* ASM type for [java.lang.Object].
*/
- internal val OBJECT_TYPE: Type by lazy { Type.getObjectType("java/lang/Object") }
+ val OBJECT_TYPE: Type by lazy { getObjectType("java/lang/Object") }
/**
* ASM type for array of [java.lang.Object].
*/
- @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "RemoveRedundantQualifierName")
- internal val OBJECT_ARRAY_TYPE: Type by lazy { Type.getType("[Ljava/lang/Object;") }
-
- /**
- * ASM type for [Algebra].
- */
- internal val ALGEBRA_TYPE: Type by lazy { Type.getObjectType("kscience/kmath/operations/Algebra") }
+ val OBJECT_ARRAY_TYPE: Type by lazy { getType("[Ljava/lang/Object;") }
/**
* ASM type for [java.lang.String].
*/
- internal val STRING_TYPE: Type by lazy { Type.getObjectType("java/lang/String") }
+ val STRING_TYPE: Type by lazy { getObjectType("java/lang/String") }
/**
* ASM type for MapIntrinsics.
*/
- internal val MAP_INTRINSICS_TYPE: Type by lazy { Type.getObjectType("kscience/kmath/asm/internal/MapIntrinsics") }
+ val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("kscience/kmath/asm/internal/MapIntrinsics") }
+
+ /**
+ * ASM Type for [kscience.kmath.expressions.Symbol].
+ */
+ val SYMBOL_TYPE: Type by lazy { getObjectType("kscience/kmath/expressions/Symbol") }
}
}
diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/MstType.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/MstType.kt
deleted file mode 100644
index 526c27305..000000000
--- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/MstType.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package kscience.kmath.asm.internal
-
-import kscience.kmath.ast.MST
-
-/**
- * Represents types known in [MST], numbers and general values.
- */
-internal enum class MstType {
- GENERAL,
- NUMBER;
-
- companion object {
- fun fromMst(mst: MST): MstType {
- if (mst is MST.Numeric)
- return NUMBER
-
- return GENERAL
- }
- }
-}
diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/codegenUtils.kt
index ef9751502..6d5d19d42 100644
--- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/codegenUtils.kt
+++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/internal/codegenUtils.kt
@@ -2,29 +2,11 @@ package kscience.kmath.asm.internal
import kscience.kmath.ast.MST
import kscience.kmath.expressions.Expression
-import kscience.kmath.operations.Algebra
-import kscience.kmath.operations.FieldOperations
-import kscience.kmath.operations.RingOperations
-import kscience.kmath.operations.SpaceOperations
import org.objectweb.asm.*
-import org.objectweb.asm.Opcodes.INVOKEVIRTUAL
import org.objectweb.asm.commons.InstructionAdapter
-import java.lang.reflect.Method
-import java.util.*
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
-private val methodNameAdapters: Map, String> by lazy {
- hashMapOf(
- SpaceOperations.PLUS_OPERATION to 2 to "add",
- RingOperations.TIMES_OPERATION to 2 to "multiply",
- FieldOperations.DIV_OPERATION to 2 to "divide",
- SpaceOperations.PLUS_OPERATION to 1 to "unaryPlus",
- SpaceOperations.MINUS_OPERATION to 1 to "unaryMinus",
- SpaceOperations.MINUS_OPERATION to 2 to "minus"
- )
-}
-
/**
* Returns ASM [Type] for given [Class].
*
@@ -109,107 +91,3 @@ internal inline fun ClassWriter.visitField(
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return visitField(access, name, descriptor, signature, value).apply(block)
}
-
-private fun AsmBuilder.findSpecific(context: Algebra, name: String, parameterTypes: Array): Method? =
- context.javaClass.methods.find { method ->
- val nameValid = method.name == name
- val arityValid = method.parameters.size == parameterTypes.size
- val notBridgeInPrimitive = !(primitiveMode && method.isBridge)
-
- val paramsValid = method.parameterTypes.zip(parameterTypes).all { (type, mstType) ->
- !(mstType != MstType.NUMBER && type == java.lang.Number::class.java)
- }
-
- nameValid && arityValid && notBridgeInPrimitive && paramsValid
- }
-
-/**
- * Checks if the target [context] for code generation contains a method with needed [name] and arity, also builds
- * type expectation stack for needed arity.
- *
- * @author Iaroslav Postovalov
- */
-private fun AsmBuilder.buildExpectationStack(
- context: Algebra,
- name: String,
- parameterTypes: Array
-): Boolean {
- val arity = parameterTypes.size
- val specific = findSpecific(context, methodNameAdapters[name to arity] ?: name, parameterTypes)
-
- if (specific != null)
- mapTypes(specific, parameterTypes).reversed().forEach { expectationStack.push(it) }
- else
- expectationStack.addAll(Collections.nCopies(arity, tType))
-
- return specific != null
-}
-
-private fun AsmBuilder.mapTypes(method: Method, parameterTypes: Array): List = method
- .parameterTypes
- .zip(parameterTypes)
- .map { (type, mstType) ->
- when {
- type == java.lang.Number::class.java && mstType == MstType.NUMBER -> AsmBuilder.NUMBER_TYPE
- else -> if (primitiveMode) primitiveMask else primitiveMaskBoxed
- }
- }
-
-/**
- * Checks if the target [context] for code generation contains a method with needed [name] and arity and inserts
- * [AsmBuilder.invokeAlgebraOperation] of this method.
- *
- * @author Iaroslav Postovalov
- */
-private fun AsmBuilder.tryInvokeSpecific(
- context: Algebra,
- name: String,
- parameterTypes: Array
-): Boolean {
- val arity = parameterTypes.size
- val theName = methodNameAdapters[name to arity] ?: name
- val spec = findSpecific(context, theName, parameterTypes) ?: return false
- val owner = context.javaClass.asm
-
- invokeAlgebraOperation(
- owner = owner.internalName,
- method = theName,
- descriptor = Type.getMethodDescriptor(primitiveMaskBoxed, *mapTypes(spec, parameterTypes).toTypedArray()),
- expectedArity = arity,
- opcode = INVOKEVIRTUAL
- )
-
- return true
-}
-
-/**
- * Builds specialized [context] call with option to fallback to generic algebra operation accepting [String].
- *
- * @author Iaroslav Postovalov
- */
-internal inline fun AsmBuilder.buildAlgebraOperationCall(
- context: Algebra,
- name: String,
- fallbackMethodName: String,
- parameterTypes: Array,
- parameters: AsmBuilder.() -> Unit
-) {
- contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) }
- val arity = parameterTypes.size
- loadAlgebra()
- if (!buildExpectationStack(context, name, parameterTypes)) loadStringConstant(name)
- parameters()
-
- if (!tryInvokeSpecific(context, name, parameterTypes)) invokeAlgebraOperation(
- owner = AsmBuilder.ALGEBRA_TYPE.internalName,
- method = fallbackMethodName,
-
- descriptor = Type.getMethodDescriptor(
- AsmBuilder.OBJECT_TYPE,
- AsmBuilder.STRING_TYPE,
- *Array(arity) { AsmBuilder.OBJECT_TYPE }
- ),
-
- expectedArity = arity
- )
-}
diff --git a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt
index 79cf77a6a..0b66e2c31 100644
--- a/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt
+++ b/kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt
@@ -1,3 +1,5 @@
+// TODO move to common when https://github.com/h0tk3y/better-parse/pull/33 is merged
+
package kscience.kmath.ast
import com.github.h0tk3y.betterParse.combinators.*
@@ -17,7 +19,8 @@ import kscience.kmath.operations.RingOperations
import kscience.kmath.operations.SpaceOperations
/**
- * TODO move to common after IR version is released
+ * better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4.
+ *
* @author Alexander Nozik and Iaroslav Postovalov
*/
public object ArithmeticsEvaluator : Grammar() {
@@ -83,7 +86,7 @@ public object ArithmeticsEvaluator : Grammar() {
}
/**
- * Tries to parse the string into [MST]. Returns [ParseResult] representing expression or error.
+ * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or error.
*
* @receiver the string to parse.
* @return the [MST] node.
@@ -91,7 +94,7 @@ public object ArithmeticsEvaluator : Grammar() {
public fun String.tryParseMath(): ParseResult = ArithmeticsEvaluator.tryParseToEnd(this)
/**
- * Parses the string into [MST].
+ * Parses the string into [MST] using [ArithmeticsEvaluator].
*
* @receiver the string to parse.
* @return the [MST] node.
diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt
similarity index 56%
rename from kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt
rename to kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt
index 5eebfe43d..ae180bf3f 100644
--- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmAlgebras.kt
+++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmConsistencyWithInterpreter.kt
@@ -1,24 +1,20 @@
package kscience.kmath.asm
-import kscience.kmath.ast.mstInField
-import kscience.kmath.ast.mstInRing
-import kscience.kmath.ast.mstInSpace
+import kscience.kmath.ast.*
import kscience.kmath.expressions.invoke
import kscience.kmath.operations.ByteRing
+import kscience.kmath.operations.ComplexField
import kscience.kmath.operations.RealField
+import kscience.kmath.operations.toComplex
import kotlin.test.Test
import kotlin.test.assertEquals
-internal class TestAsmAlgebras {
-
+internal class TestAsmConsistencyWithInterpreter {
@Test
- fun space() {
- val res1 = ByteRing.mstInSpace {
- binaryOperation(
- "+",
-
- unaryOperation(
- "+",
+ fun mstSpace() {
+ val res1 = MstSpace.mstInSpace {
+ binaryOperationFunction("+")(
+ unaryOperationFunction("+")(
number(3.toByte()) - (number(2.toByte()) + (multiply(
add(number(1), number(1)),
2
@@ -27,14 +23,11 @@ internal class TestAsmAlgebras {
number(1)
) + symbol("x") + zero
- }("x" to 2.toByte())
+ }("x" to MST.Numeric(2))
- val res2 = ByteRing.mstInSpace {
- binaryOperation(
- "+",
-
- unaryOperation(
- "+",
+ val res2 = MstSpace.mstInSpace {
+ binaryOperationFunction("+")(
+ unaryOperationFunction("+")(
number(3.toByte()) - (number(2.toByte()) + (multiply(
add(number(1), number(1)),
2
@@ -43,19 +36,16 @@ internal class TestAsmAlgebras {
number(1)
) + symbol("x") + zero
- }.compile()("x" to 2.toByte())
+ }.compile()("x" to MST.Numeric(2))
assertEquals(res1, res2)
}
@Test
- fun ring() {
+ fun byteRing() {
val res1 = ByteRing.mstInRing {
- binaryOperation(
- "+",
-
- unaryOperation(
- "+",
+ binaryOperationFunction("+")(
+ unaryOperationFunction("+")(
(symbol("x") - (2.toByte() + (multiply(
add(number(1), number(1)),
2
@@ -67,17 +57,13 @@ internal class TestAsmAlgebras {
}("x" to 3.toByte())
val res2 = ByteRing.mstInRing {
- binaryOperation(
- "+",
-
- unaryOperation(
- "+",
+ binaryOperationFunction("+")(
+ unaryOperationFunction("+")(
(symbol("x") - (2.toByte() + (multiply(
add(number(1), number(1)),
2
) + 1.toByte()))) * 3.0 - 1.toByte()
),
-
number(1)
) * number(2)
}.compile()("x" to 3.toByte())
@@ -86,10 +72,9 @@ internal class TestAsmAlgebras {
}
@Test
- fun field() {
+ fun realField() {
val res1 = RealField.mstInField {
- +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation(
- "+",
+ +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
@@ -97,8 +82,7 @@ internal class TestAsmAlgebras {
}("x" to 2.0)
val res2 = RealField.mstInField {
- +(3 - 2 + 2 * number(1) + 1.0) + binaryOperation(
- "+",
+ +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
(3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ number(1),
number(1) / 2 + number(2.0) * one
@@ -107,4 +91,25 @@ internal class TestAsmAlgebras {
assertEquals(res1, res2)
}
+
+ @Test
+ fun complexField() {
+ val res1 = ComplexField.mstInField {
+ +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
+ (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ + number(1),
+ number(1) / 2 + number(2.0) * one
+ ) + zero
+ }("x" to 2.0.toComplex())
+
+ val res2 = ComplexField.mstInField {
+ +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")(
+ (3.0 - (symbol("x") + (multiply(add(number(1.0), number(1.0)), 2) + 1.0))) * 3 - 1.0
+ + number(1),
+ number(1) / 2 + number(2.0) * one
+ ) + zero
+ }.compile()("x" to 2.0.toComplex())
+
+ assertEquals(res1, res2)
+ }
}
diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmOperationsSupport.kt
similarity index 67%
rename from kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt
rename to kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmOperationsSupport.kt
index 7f4d453f7..2ce52aa87 100644
--- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmExpressions.kt
+++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmOperationsSupport.kt
@@ -1,14 +1,15 @@
package kscience.kmath.asm
-import kscience.kmath.asm.compile
+import kscience.kmath.ast.mstInExtendedField
import kscience.kmath.ast.mstInField
import kscience.kmath.ast.mstInSpace
import kscience.kmath.expressions.invoke
import kscience.kmath.operations.RealField
+import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
-internal class TestAsmExpressions {
+internal class TestAsmOperationsSupport {
@Test
fun testUnaryOperationInvocation() {
val expression = RealField.mstInSpace { -symbol("x") }.compile()
@@ -28,4 +29,13 @@ internal class TestAsmExpressions {
val res = RealField.mstInField { symbol("x") * 2 }("x" to 2.0)
assertEquals(4.0, res)
}
+
+ @Test
+ fun testMultipleCalls() {
+ val e = RealField.mstInExtendedField { sin(symbol("x")).pow(4) - 6 * symbol("x") / tanh(symbol("x")) }.compile()
+ val r = Random(0)
+ var s = 0.0
+ repeat(1000000) { s += e("x" to r.nextDouble()) }
+ println(s)
+ }
}
diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt
index 8f8175acd..602c54651 100644
--- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt
+++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmSpecialization.kt
@@ -1,6 +1,5 @@
package kscience.kmath.asm
-import kscience.kmath.asm.compile
import kscience.kmath.ast.mstInField
import kscience.kmath.expressions.invoke
import kscience.kmath.operations.RealField
@@ -10,44 +9,44 @@ import kotlin.test.assertEquals
internal class TestAsmSpecialization {
@Test
fun testUnaryPlus() {
- val expr = RealField.mstInField { unaryOperation("+", symbol("x")) }.compile()
+ val expr = RealField.mstInField { unaryOperationFunction("+")(symbol("x")) }.compile()
assertEquals(2.0, expr("x" to 2.0))
}
@Test
fun testUnaryMinus() {
- val expr = RealField.mstInField { unaryOperation("-", symbol("x")) }.compile()
+ val expr = RealField.mstInField { unaryOperationFunction("-")(symbol("x")) }.compile()
assertEquals(-2.0, expr("x" to 2.0))
}
@Test
fun testAdd() {
- val expr = RealField.mstInField { binaryOperation("+", symbol("x"), symbol("x")) }.compile()
+ val expr = RealField.mstInField { binaryOperationFunction("+")(symbol("x"), symbol("x")) }.compile()
assertEquals(4.0, expr("x" to 2.0))
}
@Test
fun testSine() {
- val expr = RealField.mstInField { unaryOperation("sin", symbol("x")) }.compile()
+ val expr = RealField.mstInField { unaryOperationFunction("sin")(symbol("x")) }.compile()
assertEquals(0.0, expr("x" to 0.0))
}
@Test
fun testMinus() {
- val expr = RealField.mstInField { binaryOperation("-", symbol("x"), symbol("x")) }.compile()
+ val expr = RealField.mstInField { binaryOperationFunction("-")(symbol("x"), symbol("x")) }.compile()
assertEquals(0.0, expr("x" to 2.0))
}
@Test
fun testDivide() {
- val expr = RealField.mstInField { binaryOperation("/", symbol("x"), symbol("x")) }.compile()
+ val expr = RealField.mstInField { binaryOperationFunction("/")(symbol("x"), symbol("x")) }.compile()
assertEquals(1.0, expr("x" to 2.0))
}
@Test
fun testPower() {
val expr = RealField
- .mstInField { binaryOperation("power", symbol("x"), number(2)) }
+ .mstInField { binaryOperationFunction("pow")(symbol("x"), number(2)) }
.compile()
assertEquals(4.0, expr("x" to 2.0))
diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt
index 7b89c74fa..c91568dbf 100644
--- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt
+++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/asm/TestAsmVariables.kt
@@ -9,14 +9,14 @@ import kotlin.test.assertFailsWith
internal class TestAsmVariables {
@Test
- fun testVariableWithoutDefault() {
- val expr = ByteRing.mstInRing { symbol("x") }
+ fun testVariable() {
+ val expr = ByteRing.mstInRing { symbol("x") }.compile()
assertEquals(1.toByte(), expr("x" to 1.toByte()))
}
@Test
- fun testVariableWithoutDefaultFails() {
- val expr = ByteRing.mstInRing { symbol("x") }
- assertFailsWith { expr() }
+ fun testUndefinedVariableFails() {
+ val expr = ByteRing.mstInRing { symbol("x") }.compile()
+ assertFailsWith { expr() }
}
}
diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt
deleted file mode 100644
index 1ca8aa5dd..000000000
--- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/AsmTest.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package kscience.kmath.ast
-
-import kscience.kmath.asm.compile
-import kscience.kmath.asm.expression
-import kscience.kmath.ast.mstInField
-import kscience.kmath.ast.parseMath
-import kscience.kmath.expressions.invoke
-import kscience.kmath.operations.Complex
-import kscience.kmath.operations.ComplexField
-import kotlin.test.Test
-import kotlin.test.assertEquals
-
-internal class AsmTest {
- @Test
- fun `compile MST`() {
- val res = ComplexField.expression("2+2*(2+2)".parseMath())()
- assertEquals(Complex(10.0, 0.0), res)
- }
-
- @Test
- fun `compile MSTExpression`() {
- val res = ComplexField.mstInField { number(2) + number(2) * (number(2) + number(2)) }.compile()()
- assertEquals(Complex(10.0, 0.0), res)
- }
-}
diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserPrecedenceTest.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserPrecedenceTest.kt
index 1844a0991..561fe51bd 100644
--- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserPrecedenceTest.kt
+++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserPrecedenceTest.kt
@@ -1,7 +1,5 @@
package kscience.kmath.ast
-import kscience.kmath.ast.evaluate
-import kscience.kmath.ast.parseMath
import kscience.kmath.operations.Field
import kscience.kmath.operations.RealField
import kotlin.test.Test
diff --git a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt
index 2dc24597e..3aa5392c8 100644
--- a/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt
+++ b/kmath-ast/src/jvmTest/kotlin/kscience/kmath/ast/ParserTest.kt
@@ -1,8 +1,5 @@
package kscience.kmath.ast
-import kscience.kmath.ast.evaluate
-import kscience.kmath.ast.mstInField
-import kscience.kmath.ast.parseMath
import kscience.kmath.expressions.invoke
import kscience.kmath.operations.Algebra
import kscience.kmath.operations.Complex
@@ -45,12 +42,15 @@ internal class ParserTest {
val magicalAlgebra = object : Algebra {
override fun symbol(value: String): String = value
- override fun unaryOperation(operation: String, arg: String): String = throw NotImplementedError()
-
- override fun binaryOperation(operation: String, left: String, right: String): String = when (operation) {
- "magic" -> "$left ★ $right"
- else -> throw NotImplementedError()
+ override fun unaryOperationFunction(operation: String): (arg: String) -> String {
+ throw NotImplementedError()
}
+
+ override fun binaryOperationFunction(operation: String): (left: String, right: String) -> String =
+ when (operation) {
+ "magic" -> { left, right -> "$left ★ $right" }
+ else -> throw NotImplementedError()
+ }
}
val mst = "magic(a, b)".parseMath()
diff --git a/kmath-core/README.md b/kmath-core/README.md
index 3a919e85a..7882e5252 100644
--- a/kmath-core/README.md
+++ b/kmath-core/README.md
@@ -26,7 +26,7 @@ The core features of KMath:
> maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
> maven { url 'https://dl.bintray.com/mipt-npm/dev' }
> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
-
+>
> }
>
> dependencies {
diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt
index 0630e8e4b..afbaf16e1 100644
--- a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt
+++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt
@@ -7,9 +7,8 @@ import kscience.kmath.operations.*
*
* @param algebra The algebra to provide for Expressions built.
*/
-public abstract class FunctionalExpressionAlgebra>(
- public val algebra: A,
-) : ExpressionAlgebra> {
+public abstract class FunctionalExpressionAlgebra>(public val algebra: A) :
+ ExpressionAlgebra> {
/**
* Builds an Expression of constant expression which does not depend on arguments.
*/
@@ -25,19 +24,18 @@ public abstract class FunctionalExpressionAlgebra>(
/**
* Builds an Expression of dynamic call of binary operation [operation] on [left] and [right].
*/
- public override fun binaryOperation(
- operation: String,
- left: Expression,
- right: Expression,
- ): Expression = Expression { arguments ->
- algebra.binaryOperation(operation, left.invoke(arguments), right.invoke(arguments))
- }
+ public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression =
+ { left, right ->
+ Expression { arguments ->
+ algebra.binaryOperationFunction(operation)(left.invoke(arguments), right.invoke(arguments))
+ }
+ }
/**
* Builds an Expression of dynamic call of unary operation with name [operation] on [arg].
*/
- public override fun unaryOperation(operation: String, arg: Expression): Expression = Expression { arguments ->
- algebra.unaryOperation(operation, arg.invoke(arguments))
+ public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg ->
+ Expression { arguments -> algebra.unaryOperationFunction(operation)(arg.invoke(arguments)) }
}
}
@@ -52,7 +50,7 @@ public open class FunctionalExpressionSpace>(algebra: A) :
* Builds an Expression of addition of two another expressions.
*/
public override fun add(a: Expression, b: Expression): Expression =
- binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
+ binaryOperationFunction(SpaceOperations.PLUS_OPERATION)(a, b)
/**
* Builds an Expression of multiplication of expression by number.
@@ -66,11 +64,11 @@ public open class FunctionalExpressionSpace>(algebra: A) :
public operator fun T.plus(arg: Expression): Expression = arg + this
public operator fun T.minus(arg: Expression): Expression = arg - this
- public override fun unaryOperation(operation: String, arg: Expression): Expression =
- super.unaryOperation(operation, arg)
+ public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression =
+ super.unaryOperationFunction(operation)
- public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression =
- super.binaryOperation(operation, left, right)
+ public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression =
+ super.binaryOperationFunction(operation)
}
public open class FunctionalExpressionRing(algebra: A) : FunctionalExpressionSpace(algebra),
@@ -82,16 +80,16 @@ public open class FunctionalExpressionRing(algebra: A) : FunctionalExpress
* Builds an Expression of multiplication of two expressions.
*/
public override fun multiply(a: Expression, b: Expression): Expression =
- binaryOperation(RingOperations.TIMES_OPERATION, a, b)
+ binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b)
public operator fun Expression.times(arg: T): Expression = this * const(arg)
public operator fun T.times(arg: Expression): Expression = arg * this
- public override fun unaryOperation(operation: String, arg: Expression): Expression =
- super.unaryOperation(operation, arg)
+ public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression =
+ super.unaryOperationFunction(operation)
- public override fun binaryOperation(operation: String, left: Expression, right: Expression): Expression =
- super.binaryOperation(operation, left, right)
+ public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression =
+ super.binaryOperationFunction(operation)
}
public open class FunctionalExpressionField(algebra: A) :
@@ -101,49 +99,49 @@ public open class FunctionalExpressionField(algebra: A) :
* Builds an Expression of division an expression by another one.
*/
public override fun divide(a: Expression, b: Expression): Expression =
- binaryOperation(FieldOperations.DIV_OPERATION, a, b)
+ binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b)
public operator fun Expression.div(arg: T): Expression = this / const(arg)
public operator fun T.div(arg: Expression): Expression