Compare commits

...

2 Commits

Author SHA1 Message Date
f338c54632 public class methods 2025-06-10 00:09:53 +04:00
3ef80616d8 public class methods 2025-06-10 00:07:48 +04:00
6 changed files with 58 additions and 35 deletions

View File

@ -402,7 +402,9 @@ class Compiler(
} }
enum class AccessType(val isMutable: Boolean) { enum class AccessType(val isMutable: Boolean) {
Val(false), Var(true), Initialization(false) Val(false), Var(true),
@Suppress("unused")
Initialization(false)
} }
enum class Visibility { enum class Visibility {
@ -713,7 +715,6 @@ class Compiler(
cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true) cc.skipTokenOfType(Token.Type.NEWLINE, isOptional = true)
val t = cc.next() val t = cc.next()
var extraInit: Statement? = null
val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) { val bodyInit: Statement? = if (t.type == Token.Type.LBRACE) {
// parse body // parse body
parseScript(t.pos, cc).also { parseScript(t.pos, cc).also {
@ -726,10 +727,9 @@ class Compiler(
// create class // create class
val className = nameToken.value val className = nameToken.value
lateinit var classContext: Context
val defaultAccess = if (isStruct) AccessType.Var else AccessType.Initialization @Suppress("UNUSED_VARIABLE") val defaultAccess = if (isStruct) AccessType.Var else AccessType.Initialization
val defaultVisibility = Visibility.Public @Suppress("UNUSED_VARIABLE") val defaultVisibility = Visibility.Public
// create instance constructor // create instance constructor
// create custom objClass with all fields and instance constructor // create custom objClass with all fields and instance constructor
@ -741,14 +741,11 @@ class Compiler(
// the context now is a "class creation context", we must use its args to initialize // the context now is a "class creation context", we must use its args to initialize
// fields. Note that 'this' is already set by class // fields. Note that 'this' is already set by class
constructorArgsDeclaration?.let { cad -> constructorArgsDeclaration?.assignToContext(this)
cad.assignToContext(this)
// note that accessors are created in ObjClass instance, not during instance
// initialization (not here)
}
bodyInit?.execute(this) bodyInit?.execute(this)
// export public // export public
for( (name,record) in objects ) { for( (name,record) in objects ) {
println("-- $name $record")
when(record.visibility) { when(record.visibility) {
Visibility.Public -> { Visibility.Public -> {
thisObj.publicFields += name thisObj.publicFields += name

View File

@ -27,6 +27,7 @@ class Context(
fun raiseClassCastError(msg: String): Nothing = raiseError(ObjClassCastError(this, msg)) fun raiseClassCastError(msg: String): Nothing = raiseError(ObjClassCastError(this, msg))
@Suppress("unused")
fun raiseSymbolNotFound(name: String): Nothing = raiseError(ObjSymbolNotDefinedError(this, "symbol is not defined: $name")) fun raiseSymbolNotFound(name: String): Nothing = raiseError(ObjSymbolNotDefinedError(this, "symbol is not defined: $name"))
fun raiseError(message: String): Nothing { fun raiseError(message: String): Nothing {
@ -78,7 +79,7 @@ class Context(
fun getOrCreateNamespace(name: String): ObjClass { fun getOrCreateNamespace(name: String): ObjClass {
val ns = objects.getOrPut(name) { ObjRecord(ObjNamespace(name), isMutable = false) }.value val ns = objects.getOrPut(name) { ObjRecord(ObjNamespace(name), isMutable = false) }.value
return ns!!.objClass return ns.objClass
} }
inline fun addVoidFn(vararg names: String, crossinline fn: suspend Context.() -> Unit) { inline fun addVoidFn(vararg names: String, crossinline fn: suspend Context.() -> Unit) {

View File

@ -69,7 +69,7 @@ open class Obj {
args: Arguments = Arguments.EMPTY args: Arguments = Arguments.EMPTY
): T = invokeInstanceMethod(context, name, args) as T ): T = invokeInstanceMethod(context, name, args) as T
suspend fun invokeInstanceMethod( open suspend fun invokeInstanceMethod(
context: Context, context: Context,
name: String, name: String,
args: Arguments = Arguments.EMPTY args: Arguments = Arguments.EMPTY

View File

@ -46,7 +46,7 @@ class ObjClass(
) { ) {
if (name in members || allParentsSet.any { name in it.members } == true) if (name in members || allParentsSet.any { name in it.members } == true)
throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes") throw ScriptError(pos, "$name is already defined in $objClass or one of its supertypes")
members[name] = ObjRecord(initialValue, isMutable) members[name] = ObjRecord(initialValue, isMutable, visibility)
} }
fun addFn(name: String, isOpen: Boolean = false, code: suspend Context.() -> Obj) { fun addFn(name: String, isOpen: Boolean = false, code: suspend Context.() -> Obj) {
@ -151,25 +151,3 @@ val ObjArray by lazy {
} }
} }
class ObjInstance(override val objClass: ObjClass) : Obj() {
internal val publicFields = mutableSetOf<String>()
internal val protectedFields = mutableSetOf<String>()
internal lateinit var instanceContext: Context
override suspend fun readField(context: Context, name: String): ObjRecord {
return if( name in publicFields ) instanceContext[name]!!
else super.readField(context, name)
}
override suspend fun writeField(context: Context, name: String, newValue: Obj) {
if( name in publicFields ) {
val f = instanceContext[name]!!
if( !f.isMutable ) ObjIllegalAssignmentError(context, "can't reassign val $name").raise()
if( f.value.assign(context, newValue) == null)
f.value = newValue
}
else super.writeField(context, name, newValue)
}
}

View File

@ -0,0 +1,29 @@
package net.sergeych.lyng
class ObjInstance(override val objClass: ObjClass) : Obj() {
internal val publicFields = mutableSetOf<String>()
internal val protectedFields = mutableSetOf<String>()
internal lateinit var instanceContext: Context
override suspend fun readField(context: Context, name: String): ObjRecord {
return if( name in publicFields ) instanceContext[name]!!
else super.readField(context, name)
}
override suspend fun writeField(context: Context, name: String, newValue: Obj) {
if( name in publicFields ) {
val f = instanceContext[name]!!
if( !f.isMutable ) ObjIllegalAssignmentError(context, "can't reassign val $name").raise()
if( f.value.assign(context, newValue) == null)
f.value = newValue
}
else super.writeField(context, name, newValue)
}
override suspend fun invokeInstanceMethod(context: Context, name: String, args: Arguments): Obj {
if( name in publicFields ) return instanceContext[name]!!.value.invoke(context, this, args)
return super.invokeInstanceMethod(context, name, args)
}
}

View File

@ -1435,4 +1435,22 @@ class ScriptTest {
assert( p.length == 5 ) assert( p.length == 5 )
""".trimIndent()) """.trimIndent())
} }
@Test
fun testStructBodyFun() = runTest {
val c = Context()
c.eval("""
struct Point(x,y) {
fun length() {
sqrt(x*x+y*y)
}
var foo = "zero"
}
val p = Point(3,4)
assertEquals(5, p.length())
p.y = 10
println(p.length())
assertEquals(sqrt(109), p.length())
""".trimIndent())
}
} }