Skip to content

Commit af32b18

Browse files
authored
Merge pull request #52 from javecs/feature/function
ユーザー関数(Function)を実装しました。
2 parents 27fae76 + cfd7842 commit af32b18

3 files changed

Lines changed: 120 additions & 0 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package xyz.javecs.tools.expr
2+
3+
import kotlin.streams.toList
4+
5+
private val sPattern = Regex("[a-zA-Z][a-zA-Z0-9]*\\s*\\(\\s*([a-zA-Z][a-zA-Z0-9]*\\s*(,\\s*[a-zA-Z][a-zA-Z0-9]*)*)?\\s*\\)")
6+
internal fun validate(signature: String): Pair<String, Array<String>> {
7+
if (!sPattern.matches(signature.trim())) throw Exception()
8+
val separated = signature.replace(" ", "").split("(", ",", ")").stream().filter { !it.isBlank() }.toList()
9+
return Pair(separated[0], if (separated.size > 1) {
10+
separated.subList(1, separated.size).toTypedArray()
11+
} else {
12+
emptyArray()
13+
})
14+
}
15+
16+
class Function(signature: String, val codes: Array<String>) {
17+
private val calc = Calculator()
18+
val name = validate(signature).first
19+
val params = validate(signature).second
20+
fun call(args: Array<Double>): Double {
21+
if (params.size != args.size) return Double.NaN
22+
calc.clear()
23+
params.indices.forEach( { calc.eval("${params[it]} = ${args[it]}") })
24+
codes.forEach( { calc.eval(it) })
25+
return calc.value.toDouble()
26+
}
27+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package xyz.javecs.tools.expr.test.kotlin
2+
3+
import kotlin.test.assertEquals
4+
import org.junit.Test
5+
import xyz.javecs.tools.expr.Calculator
6+
import xyz.javecs.tools.expr.Function
7+
8+
class FunctionCallTest {
9+
@Test fun func1() {
10+
assertEquals(Double.NaN, Function("f(x,y)", arrayOf("x")).call(arrayOf(1.toDouble())))
11+
assertEquals(Double.NaN, Function("f(x)", arrayOf("x")).call(arrayOf(1.toDouble(), 2.toDouble())))
12+
}
13+
14+
@Test fun func2() {
15+
val f = Function("f(x,y)", arrayOf("x * y"))
16+
assertEquals(12.toDouble(), f.call(arrayOf(3.toDouble(), 4.toDouble())))
17+
assertEquals(16.toDouble(), f.call(arrayOf(4.toDouble(), 4.toDouble())))
18+
}
19+
20+
@Test fun func3() {
21+
val f = Function("f(x,y)", arrayOf("max(x,y)"))
22+
assertEquals(2.toDouble(), f.call(arrayOf(-1.toDouble(), 2.toDouble())))
23+
assertEquals(0.toDouble(), f.call(arrayOf(-1.02, 0.toDouble())))
24+
}
25+
26+
@Test fun func4() {
27+
val f = Function("f(x,y,z)", arrayOf("a = x + y + z"))
28+
assertEquals("f", f.name)
29+
assertEquals(3, f.params.size)
30+
assertEquals(5.toDouble(), f.call(arrayOf(1.toDouble(), 2.toDouble(), 2.toDouble())))
31+
}
32+
33+
@Test fun func5() {
34+
val f = Function("f(x,y,z)", arrayOf("a = x + y + z", "a = 0"))
35+
assertEquals(0.toDouble(), f.call(arrayOf(1.toDouble(), 2.toDouble(), 2.toDouble())))
36+
}
37+
38+
@Test fun func7() {
39+
val f = Function("f()", arrayOf("100"))
40+
assertEquals(100.toDouble(), f.call(emptyArray()))
41+
}
42+
}
43+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package xyz.javecs.tools.expr.test.kotlin
2+
3+
import kotlin.test.assertEquals
4+
import org.junit.Test
5+
import xyz.javecs.tools.expr.Calculator
6+
import xyz.javecs.tools.expr.Function
7+
import xyz.javecs.tools.expr.validate
8+
import kotlin.test.assertFails
9+
import kotlin.test.assertTrue
10+
11+
class FunctionSignatureTest {
12+
@Test fun signature1() {
13+
val (name, params) = validate("f(x,y)")
14+
assertEquals("f", name)
15+
assertEquals("x", params[0])
16+
assertEquals("y", params[1])
17+
}
18+
19+
@Test fun signature2() {
20+
val (name, params) = validate("f()")
21+
assertEquals("f", name)
22+
assertEquals(0, params.size)
23+
}
24+
25+
@Test fun signature3() {
26+
val (name, params) = validate("abc ( )")
27+
assertEquals("abc", name)
28+
assertEquals(0, params.size)
29+
}
30+
31+
@Test fun signature4() {
32+
val (name, params) = validate(" f123 ( abc , defh, d123456 ) ")
33+
assertEquals("f123", name)
34+
assertEquals("abc", params[0])
35+
assertEquals("defh", params[1])
36+
assertEquals("d123456", params[2])
37+
}
38+
39+
@Test fun signature5() {
40+
arrayOf(" f", "f*", "ffff(", "1()", "()", "( a )").forEach {
41+
try {
42+
validate(it)
43+
assertFails { }
44+
} catch (e: Exception) {
45+
assertTrue { true }
46+
}
47+
}
48+
}
49+
}
50+

0 commit comments

Comments
 (0)