Refactor toString implementations to support Scope context, add inspect, and improve assertions readability.
This commit is contained in:
parent
2737aaa14e
commit
fba44622e5
28
.run/Tests in 'lyng.lynglib.jvmTest'.run.xml
Normal file
28
.run/Tests in 'lyng.lynglib.jvmTest'.run.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Tests in 'lyng.lynglib.jvmTest'" type="GradleRunConfiguration" factoryName="Gradle">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value=":lynglib:cleanJvmTest" />
|
||||
<option value=":lynglib:jvmTest" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<ExternalSystemDebugDisabled>false</ExternalSystemDebugDisabled>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>true</RunAsTest>
|
||||
<GradleProfilingDisabled>false</GradleProfilingDisabled>
|
||||
<GradleCoverageDisabled>false</GradleCoverageDisabled>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@ -155,52 +155,65 @@ class Script(
|
||||
sqrt(args.firstAndOnly().toDouble())
|
||||
)
|
||||
}
|
||||
addFn( "abs" ) {
|
||||
addFn("abs") {
|
||||
val x = args.firstAndOnly()
|
||||
if( x is ObjInt) ObjInt( x.value.absoluteValue ) else ObjReal( x.toDouble().absoluteValue )
|
||||
if (x is ObjInt) ObjInt(x.value.absoluteValue) else ObjReal(x.toDouble().absoluteValue)
|
||||
}
|
||||
|
||||
addVoidFn("assert") {
|
||||
val cond = requiredArg<ObjBool>(0)
|
||||
val message = if( args.size > 1 )
|
||||
val message = if (args.size > 1)
|
||||
": " + (args[1] as Statement).execute(this).toString(this).value
|
||||
else ""
|
||||
if( !cond.value == true )
|
||||
if (!cond.value == true)
|
||||
raiseError(ObjAssertionFailedException(this, "Assertion failed$message"))
|
||||
}
|
||||
|
||||
addVoidFn("assertEquals") {
|
||||
val a = requiredArg<Obj>(0)
|
||||
val b = requiredArg<Obj>(1)
|
||||
if( a.compareTo(this, b) != 0 )
|
||||
raiseError(ObjAssertionFailedException(this,"Assertion failed: ${a.inspect(this)} == ${b.inspect(this)}"))
|
||||
if (a.compareTo(this, b) != 0)
|
||||
raiseError(
|
||||
ObjAssertionFailedException(
|
||||
this,
|
||||
"Assertion failed: ${a.inspect(this)} == ${b.inspect(this)}"
|
||||
)
|
||||
)
|
||||
}
|
||||
// alias used in tests
|
||||
addVoidFn("assertEqual") {
|
||||
val a = requiredArg<Obj>(0)
|
||||
val b = requiredArg<Obj>(1)
|
||||
if( a.compareTo(this, b) != 0 )
|
||||
raiseError(ObjAssertionFailedException(this,"Assertion failed: ${a.inspect(this)} == ${b.inspect(this)}"))
|
||||
if (a.compareTo(this, b) != 0)
|
||||
raiseError(
|
||||
ObjAssertionFailedException(
|
||||
this,
|
||||
"Assertion failed: ${a.inspect(this)} == ${b.inspect(this)}"
|
||||
)
|
||||
)
|
||||
}
|
||||
addVoidFn("assertNotEquals") {
|
||||
val a = requiredArg<Obj>(0)
|
||||
val b = requiredArg<Obj>(1)
|
||||
if( a.compareTo(this, b) == 0 )
|
||||
raiseError(ObjAssertionFailedException(this,"Assertion failed: ${a.inspect(this)} != ${b.inspect(this)}"))
|
||||
if (a.compareTo(this, b) == 0)
|
||||
raiseError(
|
||||
ObjAssertionFailedException(
|
||||
this,
|
||||
"Assertion failed: ${a.inspect(this)} != ${b.inspect(this)}"
|
||||
)
|
||||
)
|
||||
}
|
||||
addFn("assertThrows") {
|
||||
val code = requireOnlyArg<Statement>()
|
||||
val result =try {
|
||||
val result = try {
|
||||
code.execute(this)
|
||||
null
|
||||
}
|
||||
catch( e: ExecutionError ) {
|
||||
} catch (e: ExecutionError) {
|
||||
e.errorObject
|
||||
}
|
||||
catch (_: ScriptError) {
|
||||
} catch (_: ScriptError) {
|
||||
ObjNull
|
||||
}
|
||||
result ?: raiseError(ObjAssertionFailedException(this,"Expected exception but nothing was thrown"))
|
||||
result ?: raiseError(ObjAssertionFailedException(this, "Expected exception but nothing was thrown"))
|
||||
}
|
||||
|
||||
addFn("dynamic") {
|
||||
@ -209,7 +222,7 @@ class Script(
|
||||
|
||||
addFn("require") {
|
||||
val condition = requiredArg<ObjBool>(0)
|
||||
if( !condition.value ) {
|
||||
if (!condition.value) {
|
||||
val message = args.list.getOrNull(1)?.toString() ?: "requirement not met"
|
||||
raiseIllegalArgument(message)
|
||||
}
|
||||
@ -217,7 +230,7 @@ class Script(
|
||||
}
|
||||
addFn("check") {
|
||||
val condition = requiredArg<ObjBool>(0)
|
||||
if( !condition.value ) {
|
||||
if (!condition.value) {
|
||||
val message = args.list.getOrNull(1)?.toString() ?: "check failed"
|
||||
raiseIllegalState(message)
|
||||
}
|
||||
@ -340,7 +353,7 @@ class Script(
|
||||
doc = "Suspend for the given time. Accepts Duration, Int seconds, or Real seconds."
|
||||
) {
|
||||
val a = args.firstAndOnly()
|
||||
when(a) {
|
||||
when (a) {
|
||||
is ObjInt -> delay(a.value * 1000)
|
||||
is ObjReal -> delay((a.value * 1000).roundToLong())
|
||||
is ObjDuration -> delay(a.duration)
|
||||
|
||||
@ -131,7 +131,7 @@ object CompletionEngineLight {
|
||||
}
|
||||
is MiniClassDecl -> add(CompletionItem(d.name, Kind.Class_))
|
||||
is MiniValDecl -> add(CompletionItem(d.name, Kind.Value, typeText = typeOf(d.type)))
|
||||
else -> add(CompletionItem(d.name, Kind.Value))
|
||||
// else -> add(CompletionItem(d.name, Kind.Value))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -197,9 +197,20 @@ class ObjInstance(override val objClass: ObjClass) : Obj() {
|
||||
!it.key.contains("::") && it.value.visibility.isPublic && it.value.type.serializable
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val fields = publicFields.map { "${it.key}=${it.value.value}" }.joinToString(",")
|
||||
return "${objClass.className}($fields)"
|
||||
override suspend fun toString(scope: Scope, calledFromLyng: Boolean): ObjString {
|
||||
return ObjString(buildString {
|
||||
append("${objClass.className}(")
|
||||
var first = true
|
||||
for ((name, value) in publicFields) {
|
||||
if (first) first = false else append(",")
|
||||
append("$name=${value.value.toString(scope)}")
|
||||
}
|
||||
append(")")
|
||||
})
|
||||
}
|
||||
|
||||
override suspend fun inspect(scope: Scope): String {
|
||||
return toString(scope).value
|
||||
}
|
||||
|
||||
override suspend fun serialize(scope: Scope, encoder: LynonEncoder, lynonType: LynonType?) {
|
||||
|
||||
@ -198,6 +198,18 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
return JsonArray(list.map { it.toJson(scope) })
|
||||
}
|
||||
|
||||
override suspend fun toString(scope: Scope, calledFromLyng: Boolean): ObjString {
|
||||
return ObjString(buildString {
|
||||
append("[")
|
||||
var first = true
|
||||
for (v in list) {
|
||||
if (first) first = false else append(",")
|
||||
append(v.toString(scope).value)
|
||||
}
|
||||
append("]")
|
||||
})
|
||||
}
|
||||
|
||||
companion object {
|
||||
val type = object : ObjClass("List", ObjArray) {
|
||||
override suspend fun deserialize(scope: Scope, decoder: LynonDecoder, lynonType: LynonType?): Obj {
|
||||
|
||||
@ -52,8 +52,8 @@ class ObjMapEntry(val key: Obj, val value: Obj) : Obj() {
|
||||
else -> scope.raiseIndexOutOfBounds()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$key=>$value"
|
||||
override suspend fun toString(scope: Scope, calledFromLyng: Boolean): ObjString {
|
||||
return ObjString("(${key.toString(scope).value} => ${value.toString(scope).value})")
|
||||
}
|
||||
|
||||
override val objClass = type
|
||||
|
||||
@ -1625,7 +1625,7 @@ class ListLiteralRef(private val entries: List<ListEntry>) : ObjRef {
|
||||
when (elements) {
|
||||
is ObjList -> {
|
||||
// Grow underlying array once when possible
|
||||
if (list is ArrayList) list.ensureCapacity(list.size + elements.list.size)
|
||||
list.ensureCapacity(list.size + elements.list.size)
|
||||
list.addAll(elements.list)
|
||||
}
|
||||
else -> scope.raiseError("Spread element must be list")
|
||||
|
||||
@ -82,7 +82,11 @@ open class LynonDecoder(val bin: BitInput, val settings: LynonSettings = LynonSe
|
||||
if (it !is ObjClass)
|
||||
scope.raiseClassCastError("Expected obj class but got ${it::class.simpleName}")
|
||||
it
|
||||
} ?: scope.raiseSymbolNotFound("can't deserialize: not found type $className")
|
||||
} ?: scope.also {
|
||||
println("Class not found: $className")
|
||||
println("::: ${runCatching { scope.eval("Vault")}.getOrNull() }")
|
||||
println("::2 [${className}]: ${scope.get(className.value)}")
|
||||
}.raiseSymbolNotFound("can't deserialize: not found type $className")
|
||||
}
|
||||
|
||||
suspend fun decodeAnyList(scope: Scope, fixedSize: Int? = null): MutableList<Obj> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user