diff --git a/docs/OOP.md b/docs/OOP.md index 14ab2e6..faef0a3 100644 --- a/docs/OOP.md +++ b/docs/OOP.md @@ -40,14 +40,28 @@ Class is the object, naturally, with class: Classes can be compared: - println(1.21::class == Math.PI::class) - println(3.14::class == 1::class) - println(π::class) - >>> true - >>> false + assert(1.21::class == Math.PI::class) + assert(3.14::class != 1::class) + assert(π::class == Real) + π::class >>> Real + +Note `Real` class: it is global variable for Real class; there are such class instances for all built-in types: + + assert("Hello"::class == String) + assert(1970::class == Int) + assert(true::class == Bool) >>> void +More complex is singleton classes, because you don't need to compare their class +instances and generally don't need them at all, these are normally just Obj: + + null::class + >>> Obj + +At this time, `Obj` can't be accessed as a class. + + ### Methods in-depth Regular methods are called on instances as usual `instance.method()`. The method resolution order is diff --git a/docs/Real.md b/docs/Real.md new file mode 100644 index 0000000..361f3c9 --- /dev/null +++ b/docs/Real.md @@ -0,0 +1,25 @@ +# Real built-in class + +Class that supports double-precision math. Woks much like double in other languages. We honor no floats, so it is ' +Real'. + +It's class in Ling is `Real`: + + (π/2)::class + >>> Real + +you can use it's class to ensure type: + + 1.71::class == Real + >>> true + +## Member functions + +| name | meaning | type | +|--------------|------------------------------------|------| +| `roundToInt` | round to nearest int like round(x) | Int | +| | | | +| | | | +| | | | +| | | | +| | | | diff --git a/library/src/commonMain/kotlin/net/sergeych/ling/Arguments.kt b/library/src/commonMain/kotlin/net/sergeych/ling/Arguments.kt index ee588cc..e44c906 100644 --- a/library/src/commonMain/kotlin/net/sergeych/ling/Arguments.kt +++ b/library/src/commonMain/kotlin/net/sergeych/ling/Arguments.kt @@ -13,6 +13,12 @@ data class Arguments(val list: List): Iterable { return list.first().value } + inline fun required(index: Int, context: Context): T { + if( list.size <= index ) context.raiseError("Expected at least ${index+1} argument, got ${list.size}") + return (list[index].value as? T) + ?: context.raiseError("Expected type ${T::class.simpleName}, got ${list[index].value::class.simpleName}") + } + companion object { val EMPTY = Arguments(emptyList()) } diff --git a/library/src/commonMain/kotlin/net/sergeych/ling/Context.kt b/library/src/commonMain/kotlin/net/sergeych/ling/Context.kt index eea92b9..b229f02 100644 --- a/library/src/commonMain/kotlin/net/sergeych/ling/Context.kt +++ b/library/src/commonMain/kotlin/net/sergeych/ling/Context.kt @@ -67,7 +67,7 @@ class Context( } } - inline fun addConst(value: T, vararg names: String) { + inline fun addConstWithAliases(value: T, vararg names: String) { val obj = Obj.from(value) for (name in names) { addItem( @@ -78,6 +78,8 @@ class Context( } } + fun addConst(name: String,value: Obj) = addItem(name, false, value) + suspend fun eval(code: String): Obj = Compiler().compile(code.toSource()).execute(this) diff --git a/library/src/commonMain/kotlin/net/sergeych/ling/Obj.kt b/library/src/commonMain/kotlin/net/sergeych/ling/Obj.kt index a8b76d0..9697631 100644 --- a/library/src/commonMain/kotlin/net/sergeych/ling/Obj.kt +++ b/library/src/commonMain/kotlin/net/sergeych/ling/Obj.kt @@ -190,6 +190,13 @@ data class ObjString(val value: String) : Obj() { } override fun toString(): String = value + + override val objClass: ObjClass + get() = type + + companion object { + val type = ObjClass("String") + } } interface Numeric { @@ -273,10 +280,14 @@ data class ObjInt(var value: Long) : Obj(), Numeric { } override fun toString(): String = value.toString() + + override val objClass: ObjClass = type + + companion object { + val type = ObjClass("Int") + } } -@Serializable -@SerialName("bool") data class ObjBool(val value: Boolean) : Obj() { override val asStr by lazy { ObjString(value.toString()) } @@ -286,6 +297,12 @@ data class ObjBool(val value: Boolean) : Obj() { } override fun toString(): String = value.toString() + + override val objClass: ObjClass = type + + companion object { + val type = ObjClass("Bool") + } } data class ObjNamespace(val name: String) : Obj() { @@ -300,3 +317,4 @@ open class ObjError(val context: Context, val message: String) : Obj() { class ObjNullPointerError(context: Context) : ObjError(context, "object is null") +class ObjAssertionError(context: Context, message: String) : ObjError(context, message) diff --git a/library/src/commonMain/kotlin/net/sergeych/ling/Script.kt b/library/src/commonMain/kotlin/net/sergeych/ling/Script.kt index 659fd45..3c5a8b6 100644 --- a/library/src/commonMain/kotlin/net/sergeych/ling/Script.kt +++ b/library/src/commonMain/kotlin/net/sergeych/ling/Script.kt @@ -21,8 +21,8 @@ class Script( val defaultContext: Context = Context().apply { addFn("println") { print("yn: ") - for( (i,a) in args.withIndex() ) { - if( i > 0 ) print(' ' + a.asStr.value) + for ((i, a) in args.withIndex()) { + if (i > 0) print(' ' + a.asStr.value) else print(a.asStr.value) } println() @@ -30,28 +30,39 @@ class Script( } addFn("floor") { val x = args.firstAndOnly() - if( x is ObjInt ) x + if (x is ObjInt) x else ObjReal(floor(x.toDouble())) } addFn("ceil") { val x = args.firstAndOnly() - if( x is ObjInt ) x + if (x is ObjInt) x else ObjReal(ceil(x.toDouble())) } addFn("round") { val x = args.firstAndOnly() - if( x is ObjInt ) x + if (x is ObjInt) x else ObjReal(round(x.toDouble())) } addFn("sin") { sin(args.firstAndOnly().toDouble()) } + + addFn("assert") { + val cond = args.required(0, this) + if( !cond.value == true ) + raiseError(ObjAssertionError(this,"Assertion failed")) + } + + addConst("Real", ObjReal.type) + addConst("String", ObjString.type) + addConst("Int", ObjInt.type) + addConst("Bool", ObjBool.type) val pi = ObjReal(PI) val z = pi.objClass println("PI class $z") - addConst(pi, "π") + addConst("π", pi) getOrCreateNamespace("Math").apply { - addConst( "PI", pi) + addConst("PI", pi) } } } diff --git a/library/src/jvmTest/kotlin/BookTest.kt b/library/src/jvmTest/kotlin/BookTest.kt index 46be28e..0e40fc2 100644 --- a/library/src/jvmTest/kotlin/BookTest.kt +++ b/library/src/jvmTest/kotlin/BookTest.kt @@ -189,7 +189,13 @@ class BookTest { } @Test - fun testsFromOOPrinciples() = runTest { + fun testsFromOOP() = runTest { runDocTests("../docs/OOP.md") } + + @Test + fun testFromReal() = runTest { + runDocTests("../docs/real.md") + } + } \ No newline at end of file