converted namespaces to objects (coming to static objects, singletons)
This commit is contained in:
parent
d21544ca5d
commit
f885300d18
@ -40,7 +40,7 @@ Class is the object, naturally, with class:
|
||||
|
||||
Classes can be compared:
|
||||
|
||||
println(3.14::class == 2.21::class)
|
||||
println(1.21::class == Math.PI::class)
|
||||
println(3.14::class == 1::class)
|
||||
println(π::class)
|
||||
>>> true
|
||||
|
@ -89,14 +89,14 @@ class CompilerContext(val tokens: List<Token>) : ListIterator<Token> by tokens.l
|
||||
} else true
|
||||
}
|
||||
|
||||
fun ifNextIs(typeId: Token.Type, f: (Token) -> Unit): IfScope {
|
||||
fun ifNextIs(typeId: Token.Type, f: (Token) -> Unit): Boolean {
|
||||
val t = next()
|
||||
return if (t.type == typeId) {
|
||||
f(t)
|
||||
IfScope(true)
|
||||
true
|
||||
} else {
|
||||
previous()
|
||||
IfScope(false)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,22 +277,28 @@ class Compiler {
|
||||
Token.Type.DOT -> {
|
||||
operand?.let { left ->
|
||||
// dotcall: calling method on the operand, if next is ID, "("
|
||||
cc.ifNextIs(Token.Type.ID) { methodToken ->
|
||||
var isCall = false
|
||||
val next = cc.next()
|
||||
if( next.type == Token.Type.ID) {
|
||||
cc.ifNextIs(Token.Type.LPAREN) {
|
||||
// instance method call
|
||||
val args = parseArgs(cc)
|
||||
isCall = true
|
||||
operand = Accessor { context ->
|
||||
context.pos = methodToken.pos
|
||||
context.pos = next.pos
|
||||
val v = left.getter(context)
|
||||
v.callInstanceMethod(
|
||||
context,
|
||||
methodToken.value,
|
||||
next.value,
|
||||
args.toArguments()
|
||||
)
|
||||
}
|
||||
}
|
||||
}.otherwise {
|
||||
TODO("implement member access")
|
||||
}
|
||||
if (!isCall) {
|
||||
operand = Accessor { context ->
|
||||
left.getter(context).readField(context, next.value)
|
||||
}
|
||||
}
|
||||
} ?: throw ScriptError(t.pos, "Expecting expression before dot")
|
||||
}
|
||||
@ -489,7 +495,10 @@ class Compiler {
|
||||
else -> {
|
||||
Accessor({
|
||||
it.pos = t.pos
|
||||
it.get(t.value)?.value ?: it.raiseError("symbol not defined: '${t.value}'")
|
||||
it.get(t.value)?.value?.also {
|
||||
println("got ${t.value} -> $it")
|
||||
}
|
||||
?: it.raiseError("symbol not defined: '${t.value}'")
|
||||
}) { ctx, newValue ->
|
||||
ctx.get(t.value)?.let { stored ->
|
||||
ctx.pos = t.pos
|
||||
|
@ -37,14 +37,13 @@ class Context(
|
||||
objects.put(name, StoredObj(value, isMutable))
|
||||
}
|
||||
|
||||
fun getOrCreateNamespace(name: String) =
|
||||
fun getOrCreateNamespace(name: String): ObjNamespace =
|
||||
(objects.getOrPut(name) {
|
||||
StoredObj(
|
||||
ObjNamespace(name, copy(pos)),
|
||||
ObjNamespace(name),
|
||||
isMutable = false
|
||||
)
|
||||
}.value as ObjNamespace)
|
||||
.context
|
||||
|
||||
inline fun <reified T> addFn(vararg names: String, crossinline fn: suspend Context.() -> T) {
|
||||
val newFn = object : Statement() {
|
||||
|
@ -26,9 +26,12 @@ sealed class Obj {
|
||||
private val monitor = Mutex()
|
||||
|
||||
// members: fields most often
|
||||
internal val members = mutableMapOf<String, WithAccess<Obj>>()
|
||||
private val members = mutableMapOf<String, WithAccess<Obj>>()
|
||||
|
||||
// private val memberMutex = Mutex()
|
||||
private val parentInstances = listOf<Obj>()
|
||||
|
||||
|
||||
/**
|
||||
* Get instance member traversing the hierarchy if needed. Its meaning is different for different objects.
|
||||
*/
|
||||
@ -38,15 +41,18 @@ sealed class Obj {
|
||||
return null
|
||||
}
|
||||
|
||||
fun getInstanceMember(atPos: Pos, name: String): Obj = getInstanceMemberOrNull(name)
|
||||
fun getInstanceMember(atPos: Pos, name: String): Obj =
|
||||
getInstanceMemberOrNull(name)
|
||||
?: throw ScriptError(atPos, "symbol doesn't exist: $name")
|
||||
|
||||
suspend fun callInstanceMethod(context: Context, name: String,args: Arguments): Obj {
|
||||
suspend fun callInstanceMethod(context: Context, name: String, args: Arguments): Obj =
|
||||
// instance _methods_ are our ObjClass instance:
|
||||
// note that getInstanceMember traverses the hierarchy
|
||||
return objClass.getInstanceMember(context.pos,name).invoke(context, this, args)
|
||||
}
|
||||
|
||||
// instance _methods_ are our ObjClass instance:
|
||||
// note that getInstanceMember traverses the hierarchy
|
||||
// instance _methods_ are our ObjClass instance:
|
||||
// note that getInstanceMember traverses the hierarchy
|
||||
objClass.getInstanceMember(context.pos, name).invoke(context, this, args)
|
||||
|
||||
// methods that to override
|
||||
|
||||
@ -99,14 +105,22 @@ sealed class Obj {
|
||||
|
||||
suspend fun <T> sync(block: () -> T): T = monitor.withLock { block() }
|
||||
|
||||
open suspend fun readField(context: Context, name: String): Obj {
|
||||
context.raiseNotImplemented()
|
||||
suspend fun readField(context: Context, name: String): Obj = getInstanceMember(context.pos, name)
|
||||
|
||||
suspend fun writeField(context: Context, name: String, newValue: Obj) {
|
||||
willMutate(context)
|
||||
members[name]?.let { if (it.isMutable) it.value = newValue }
|
||||
?: context.raiseError("Can't reassign member: $name")
|
||||
}
|
||||
|
||||
open suspend fun writeField(context: Context,name: String, newValue: Obj) {
|
||||
context.raiseNotImplemented()
|
||||
fun createField(name: String, initialValue: Obj, isMutable: Boolean = false, pos: Pos = Pos.builtIn) {
|
||||
if (name in members || parentInstances.any<Obj> { name in it.members })
|
||||
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
|
||||
members[name] = WithAccess(initialValue, isMutable)
|
||||
}
|
||||
|
||||
fun addConst(name: String, value: Obj) = createField(name, value, isMutable = false)
|
||||
|
||||
open suspend fun callOn(context: Context): Obj {
|
||||
context.raiseNotImplemented()
|
||||
}
|
||||
@ -202,7 +216,6 @@ fun Obj.toBool(): Boolean =
|
||||
(this as? ObjBool)?.value ?: throw IllegalArgumentException("cannot convert to boolean $this")
|
||||
|
||||
|
||||
|
||||
data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
override val asStr by lazy { ObjString(value.toString()) }
|
||||
override val longValue: Long by lazy { floor(value).toLong() }
|
||||
@ -221,11 +234,11 @@ data class ObjReal(val value: Double) : Obj(), Numeric {
|
||||
|
||||
companion object {
|
||||
val type: ObjClass = ObjClass("Real").apply {
|
||||
members["roundToInt"] = WithAccess(
|
||||
createField(
|
||||
"roundToInt",
|
||||
statement(Pos.builtIn) {
|
||||
(it.thisObj as ObjReal).value.roundToLong().toObj()
|
||||
},
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -275,15 +288,10 @@ data class ObjBool(val value: Boolean) : Obj() {
|
||||
override fun toString(): String = value.toString()
|
||||
}
|
||||
|
||||
data class ObjNamespace(val name: String, val context: Context) : Obj() {
|
||||
data class ObjNamespace(val name: String) : Obj() {
|
||||
override fun toString(): String {
|
||||
return "namespace ${name}"
|
||||
}
|
||||
|
||||
override suspend fun readField(callerContext: Context,name: String): Obj {
|
||||
return context[name]?.value ?: callerContext.raiseError("not found: $name")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open class ObjError(val context: Context, val message: String) : Obj() {
|
||||
@ -291,3 +299,4 @@ open class ObjError(val context: Context, val message: String) : Obj() {
|
||||
}
|
||||
|
||||
class ObjNullPointerError(context: Context) : ObjError(context, "object is null")
|
||||
|
||||
|
@ -50,8 +50,8 @@ class Script(
|
||||
val z = pi.objClass
|
||||
println("PI class $z")
|
||||
addConst(pi, "π")
|
||||
getOrCreateNamespace("Math").also { ns ->
|
||||
ns.addConst(pi, "PI")
|
||||
getOrCreateNamespace("Math").apply {
|
||||
addConst( "PI", pi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user