fix #34 minimal time manipulation
This commit is contained in:
1 parent
23006b5caa
commit
732d8f3877
14 files changed
+478
-16
No files matched your search
@@ -42,6 +42,9 @@ data class Arguments(val list: List<Obj>,val tailBlockMode: Boolean = false) : L
|
||||
return list.map { it.toKotlin(scope) }
|
||||
}
|
||||
|
||||
fun inspect(): String = list.joinToString(", ") { it.inspect() }
|
||||
|
||||
|
||||
companion object {
|
||||
val EMPTY = Arguments(emptyList())
|
||||
fun from(values: Collection<Obj>) = Arguments(values.toList())
|
||||
|
||||
@@ -751,7 +751,7 @@ class Compiler(
|
||||
val t = cc.next()
|
||||
return when (t.type) {
|
||||
Token.Type.INT, Token.Type.HEX -> {
|
||||
val n = t.value.toLong(if (t.type == Token.Type.HEX) 16 else 10)
|
||||
val n = t.value.replace("_", "").toLong(if (t.type == Token.Type.HEX) 16 else 10)
|
||||
if (isPlus) ObjInt(n) else ObjInt(-n)
|
||||
}
|
||||
|
||||
|
||||
@@ -320,6 +320,8 @@ open class Obj {
|
||||
}
|
||||
}
|
||||
|
||||
fun Double.toObj(): Obj = ObjReal(this)
|
||||
|
||||
@Suppress("unused")
|
||||
inline fun <reified T> T.toObj(): Obj = Obj.from(this)
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
val start: Int = index.startInt(scope)
|
||||
val end: Int = index.exclusiveIntEnd(scope) ?: size
|
||||
ObjBuffer(byteArray.sliceArray(start..<end))
|
||||
}
|
||||
else ObjInt(byteArray[checkIndex(scope, index)].toLong(), true)
|
||||
} else ObjInt(byteArray[checkIndex(scope, index)].toLong(), true)
|
||||
}
|
||||
|
||||
override suspend fun putAt(scope: Scope, index: Obj, newValue: Obj) {
|
||||
@@ -42,7 +41,7 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
val size by byteArray::size
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if (other !is ObjBuffer) return -1
|
||||
if (other !is ObjBuffer) return super.compareTo(scope, other)
|
||||
val limit = min(size, other.size)
|
||||
for (i in 0..<limit) {
|
||||
val own = byteArray[i]
|
||||
@@ -56,11 +55,12 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
}
|
||||
|
||||
override suspend fun plus(scope: Scope, other: Obj): Obj {
|
||||
return if( other is ObjBuffer)
|
||||
return if (other is ObjBuffer)
|
||||
ObjBuffer(byteArray + other.byteArray)
|
||||
else if( other.isInstanceOf(ObjIterable)) {
|
||||
else if (other.isInstanceOf(ObjIterable)) {
|
||||
ObjBuffer(
|
||||
byteArray + other.toFlow(scope).map { it.toLong().toUByte() }.toList().toTypedArray().toUByteArray()
|
||||
byteArray + other.toFlow(scope).map { it.toLong().toUByte() }.toList().toTypedArray()
|
||||
.toUByteArray()
|
||||
)
|
||||
} else scope.raiseIllegalArgument("can't concatenate buffer with ${other.inspect()}")
|
||||
}
|
||||
@@ -84,7 +84,8 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||
else -> {
|
||||
if (obj.isInstanceOf(ObjIterable)) {
|
||||
ObjBuffer(
|
||||
obj.toFlow(scope).map { it.toLong().toUByte() }.toList().toTypedArray().toUByteArray()
|
||||
obj.toFlow(scope).map { it.toLong().toUByte() }.toList().toTypedArray()
|
||||
.toUByteArray()
|
||||
)
|
||||
} else
|
||||
scope.raiseIllegalArgument(
|
||||
|
||||
@@ -4,7 +4,7 @@ val ObjClassType by lazy { ObjClass("Class") }
|
||||
|
||||
open class ObjClass(
|
||||
val className: String,
|
||||
vararg val parents: ObjClass,
|
||||
vararg parents: ObjClass,
|
||||
) : Obj() {
|
||||
|
||||
var instanceConstructor: Statement? = null
|
||||
@@ -18,6 +18,7 @@ open class ObjClass(
|
||||
|
||||
// members: fields most often
|
||||
private val members = mutableMapOf<String, ObjRecord>()
|
||||
private val classMembers = mutableMapOf<String, ObjRecord>()
|
||||
|
||||
override fun toString(): String = className
|
||||
|
||||
@@ -32,9 +33,9 @@ open class ObjClass(
|
||||
return instance
|
||||
}
|
||||
|
||||
fun defaultInstance(): Obj = object : Obj() {
|
||||
override val objClass: ObjClass = this@ObjClass
|
||||
}
|
||||
// fun defaultInstance(): Obj = object : Obj() {
|
||||
// override val objClass: ObjClass = this@ObjClass
|
||||
// }
|
||||
|
||||
fun createField(
|
||||
name: String,
|
||||
@@ -49,11 +50,25 @@ open class ObjClass(
|
||||
members[name] = ObjRecord(initialValue, isMutable, visibility)
|
||||
}
|
||||
|
||||
fun createClassField(
|
||||
name: String,
|
||||
initialValue: Obj,
|
||||
isMutable: Boolean = false,
|
||||
visibility: Visibility = Visibility.Public,
|
||||
pos: Pos = Pos.builtIn
|
||||
) {
|
||||
val existing = classMembers[name]
|
||||
if( existing != null)
|
||||
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
|
||||
classMembers[name] = ObjRecord(initialValue, isMutable, visibility)
|
||||
}
|
||||
|
||||
fun addFn(name: String, isOpen: Boolean = false, code: suspend Scope.() -> Obj) {
|
||||
createField(name, statement { code() }, isOpen)
|
||||
}
|
||||
|
||||
fun addConst(name: String, value: Obj) = createField(name, value, isMutable = false)
|
||||
fun addClassConst(name: String, value: Obj) = createClassField(name, value)
|
||||
|
||||
|
||||
/**
|
||||
@@ -68,6 +83,14 @@ open class ObjClass(
|
||||
fun getInstanceMember(atPos: Pos, name: String): ObjRecord =
|
||||
getInstanceMemberOrNull(name)
|
||||
?: throw ScriptError(atPos, "symbol doesn't exist: $name")
|
||||
|
||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||
classMembers[name]?.let {
|
||||
println("class field $it")
|
||||
return it
|
||||
}
|
||||
return super.readField(scope, name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
package net.sergeych.lyng
|
||||
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.DurationUnit
|
||||
|
||||
class ObjDuration(val duration: Duration) : Obj() {
|
||||
override val objClass: ObjClass = type
|
||||
|
||||
override fun toString(): String {
|
||||
return duration.toString()
|
||||
}
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
return if( other is ObjDuration)
|
||||
duration.compareTo(other.duration)
|
||||
else -1
|
||||
}
|
||||
|
||||
companion object {
|
||||
val type = object : ObjClass("Duration") {
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
val args = scope.args
|
||||
if( args.list.size > 1 )
|
||||
scope.raiseIllegalArgument("can't construct Duration(${args.inspect()})")
|
||||
val a0 = args.list.getOrNull(0)
|
||||
|
||||
return ObjDuration(
|
||||
when (a0) {
|
||||
null -> Duration.ZERO
|
||||
is ObjInt -> a0.value.seconds
|
||||
is ObjReal -> a0.value.seconds
|
||||
else -> {
|
||||
scope.raiseIllegalArgument("can't construct Instant(${args.inspect()})")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}.apply {
|
||||
addFn("days") {
|
||||
thisAs<ObjDuration>().duration.toDouble(DurationUnit.DAYS).toObj()
|
||||
}
|
||||
addFn("hours") {
|
||||
thisAs<ObjDuration>().duration.toDouble(DurationUnit.HOURS).toObj()
|
||||
}
|
||||
addFn("minutes") {
|
||||
thisAs<ObjDuration>().duration.toDouble(DurationUnit.MINUTES).toObj()
|
||||
}
|
||||
addFn("seconds") {
|
||||
thisAs<ObjDuration>().duration.toDouble(DurationUnit.SECONDS).toObj()
|
||||
}
|
||||
addFn("milliseconds") {
|
||||
thisAs<ObjDuration>().duration.toDouble(DurationUnit.MILLISECONDS).toObj()
|
||||
}
|
||||
ObjInt.type.addFn("seconds") {
|
||||
ObjDuration(thisAs<ObjInt>().value.seconds)
|
||||
}
|
||||
|
||||
ObjInt.type.addFn("second") {
|
||||
ObjDuration(thisAs<ObjInt>().value.seconds)
|
||||
}
|
||||
|
||||
ObjInt.type.addFn("milliseconds") {
|
||||
ObjDuration(thisAs<ObjInt>().value.milliseconds)
|
||||
}
|
||||
|
||||
ObjInt.type.addFn("millisecond") {
|
||||
ObjDuration(thisAs<ObjInt>().value.milliseconds)
|
||||
}
|
||||
|
||||
ObjReal.type.addFn("seconds") {
|
||||
ObjDuration(thisAs<ObjReal>().value.seconds)
|
||||
}
|
||||
|
||||
ObjReal.type.addFn("second") {
|
||||
ObjDuration(thisAs<ObjReal>().value.seconds)
|
||||
}
|
||||
|
||||
ObjReal.type.addFn("milliseconds") {
|
||||
ObjDuration(thisAs<ObjReal>().value.milliseconds)
|
||||
}
|
||||
ObjReal.type.addFn("millisecond") {
|
||||
ObjDuration(thisAs<ObjReal>().value.milliseconds)
|
||||
}
|
||||
|
||||
ObjInt.type.addFn("minutes") {
|
||||
ObjDuration(thisAs<ObjInt>().value.minutes)
|
||||
}
|
||||
ObjReal.type.addFn("minutes") {
|
||||
ObjDuration(thisAs<ObjReal>().value.minutes)
|
||||
}
|
||||
ObjInt.type.addFn("minute") {
|
||||
ObjDuration(thisAs<ObjInt>().value.minutes)
|
||||
}
|
||||
ObjReal.type.addFn("minute") {
|
||||
ObjDuration(thisAs<ObjReal>().value.minutes)
|
||||
}
|
||||
ObjInt.type.addFn("hours") {
|
||||
ObjDuration(thisAs<ObjInt>().value.hours)
|
||||
}
|
||||
ObjReal.type.addFn("hours") {
|
||||
ObjDuration(thisAs<ObjReal>().value.hours)
|
||||
}
|
||||
ObjInt.type.addFn("hour") {
|
||||
ObjDuration(thisAs<ObjInt>().value.hours)
|
||||
}
|
||||
ObjReal.type.addFn("hour") {
|
||||
ObjDuration(thisAs<ObjReal>().value.hours)
|
||||
}
|
||||
ObjInt.type.addFn("days") {
|
||||
ObjDuration(thisAs<ObjInt>().value.days)
|
||||
}
|
||||
ObjReal.type.addFn("days") {
|
||||
ObjDuration(thisAs<ObjReal>().value.days)
|
||||
}
|
||||
ObjInt.type.addFn("day") {
|
||||
ObjDuration(thisAs<ObjInt>().value.days)
|
||||
}
|
||||
ObjReal.type.addFn("day") {
|
||||
ObjDuration(thisAs<ObjReal>().value.days)
|
||||
}
|
||||
|
||||
|
||||
// addFn("epochSeconds") {
|
||||
// val instant = thisAs<ObjInstant>().instant
|
||||
// ObjReal(instant.epochSeconds + instant.nanosecondsOfSecond * 1e-9)
|
||||
// }
|
||||
// addFn("epochMilliseconds") {
|
||||
// ObjInt(instant.toEpochMilliseconds())
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package net.sergeych.lyng
|
||||
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.isDistantFuture
|
||||
import kotlinx.datetime.isDistantPast
|
||||
|
||||
class ObjInstant(val instant: Instant) : Obj() {
|
||||
override val objClass: ObjClass get() = type
|
||||
|
||||
override fun toString(): String {
|
||||
return instant.toString()
|
||||
}
|
||||
|
||||
override suspend fun plus(scope: Scope, other: Obj): Obj {
|
||||
return when (other) {
|
||||
is ObjDuration -> ObjInstant(instant + other.duration)
|
||||
else -> super.plus(scope, other)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun minus(scope: Scope, other: Obj): Obj {
|
||||
return when (other) {
|
||||
is ObjDuration -> ObjInstant(instant - other.duration)
|
||||
is ObjInstant -> ObjDuration(instant - other.instant)
|
||||
else -> super.plus(scope, other)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun compareTo(scope: Scope, other: Obj): Int {
|
||||
if( other is ObjInstant) {
|
||||
return instant.compareTo(other.instant)
|
||||
}
|
||||
return super.compareTo(scope, other)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val distantFuture by lazy {
|
||||
ObjInstant(Instant.DISTANT_FUTURE)
|
||||
}
|
||||
|
||||
val distantPast by lazy {
|
||||
ObjInstant(Instant.DISTANT_PAST)
|
||||
}
|
||||
|
||||
val type = object : ObjClass("Instant") {
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
val args = scope.args
|
||||
val a0 = args.list.getOrNull(0)
|
||||
return ObjInstant(
|
||||
when (a0) {
|
||||
null -> {
|
||||
val t = Clock.System.now()
|
||||
Instant.fromEpochSeconds(t.epochSeconds, (t.nanosecondsOfSecond / 1_000_000).toLong()*1_000_000)
|
||||
}
|
||||
is ObjInt -> Instant.fromEpochSeconds(a0.value)
|
||||
is ObjReal -> {
|
||||
val seconds = a0.value.toLong()
|
||||
val nanos = (a0.value - seconds) * 1e9
|
||||
Instant.fromEpochSeconds(seconds, nanos.toLong())
|
||||
}
|
||||
is ObjInstant -> a0.instant
|
||||
|
||||
else -> {
|
||||
scope.raiseIllegalArgument("can't construct Instant(${args.inspect()})")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}.apply {
|
||||
addFn("epochSeconds") {
|
||||
val instant = thisAs<ObjInstant>().instant
|
||||
ObjReal(instant.epochSeconds + instant.nanosecondsOfSecond * 1e-9)
|
||||
}
|
||||
addFn("isDistantFuture") {
|
||||
thisAs<ObjInstant>().instant.isDistantFuture.toObj()
|
||||
}
|
||||
addFn("isDistantPast") {
|
||||
thisAs<ObjInstant>().instant.isDistantPast.toObj()
|
||||
}
|
||||
addClassConst("distantFuture", distantFuture)
|
||||
addClassConst("distantPast", distantPast)
|
||||
// addFn("epochMilliseconds") {
|
||||
// ObjInt(instant.toEpochMilliseconds())
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ private class Parser(fromPos: Pos) {
|
||||
|
||||
in digitsSet -> {
|
||||
pos.back()
|
||||
decodeNumber(loadChars(digits), from)
|
||||
decodeNumber(loadChars { it in digitsSet || it == '_'}, from)
|
||||
}
|
||||
|
||||
'\'' -> {
|
||||
|
||||
@@ -179,6 +179,20 @@ class Script(
|
||||
addPackage("lyng.buffer") {
|
||||
it.addConst("Buffer", ObjBuffer.type)
|
||||
}
|
||||
addPackage("lyng.time") {
|
||||
it.addConst("Instant", ObjInstant.type)
|
||||
it.addConst("Duration", ObjDuration.type)
|
||||
it.addFn("delay") {
|
||||
val a = args.firstAndOnly()
|
||||
when(a) {
|
||||
is ObjInt -> delay(a.value * 1000)
|
||||
is ObjReal -> delay((a.value * 1000).roundToLong())
|
||||
is ObjDuration -> delay(a.duration)
|
||||
else -> raiseIllegalArgument("Expected Duration, Int or Real, got ${a.inspect()}")
|
||||
}
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user