Add variance-aware type params and generic delegates
This commit is contained in:
parent
c9da0b256f
commit
c5bf4e5039
@ -23,9 +23,12 @@ sealed class CodeContext {
|
|||||||
val name: String,
|
val name: String,
|
||||||
val implicitThisMembers: Boolean = false,
|
val implicitThisMembers: Boolean = false,
|
||||||
val implicitThisTypeName: String? = null,
|
val implicitThisTypeName: String? = null,
|
||||||
val typeParams: Set<String> = emptySet()
|
val typeParams: Set<String> = emptySet(),
|
||||||
|
val typeParamDecls: List<TypeDecl.TypeParam> = emptyList()
|
||||||
): CodeContext()
|
): CodeContext()
|
||||||
class ClassBody(val name: String, val isExtern: Boolean = false): CodeContext() {
|
class ClassBody(val name: String, val isExtern: Boolean = false): CodeContext() {
|
||||||
|
var typeParams: Set<String> = emptySet()
|
||||||
|
var typeParamDecls: List<TypeDecl.TypeParam> = emptyList()
|
||||||
val pendingInitializations = mutableMapOf<String, Pos>()
|
val pendingInitializations = mutableMapOf<String, Pos>()
|
||||||
val declaredMembers = mutableSetOf<String>()
|
val declaredMembers = mutableSetOf<String>()
|
||||||
val memberOverrides = mutableMapOf<String, Boolean>()
|
val memberOverrides = mutableMapOf<String, Boolean>()
|
||||||
|
|||||||
@ -439,11 +439,56 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun currentTypeParams(): Set<String> {
|
private fun currentTypeParams(): Set<String> {
|
||||||
|
val result = mutableSetOf<String>()
|
||||||
for (ctx in codeContexts.asReversed()) {
|
for (ctx in codeContexts.asReversed()) {
|
||||||
val fn = ctx as? CodeContext.Function ?: continue
|
when (ctx) {
|
||||||
if (fn.typeParams.isNotEmpty()) return fn.typeParams
|
is CodeContext.Function -> result.addAll(ctx.typeParams)
|
||||||
|
is CodeContext.ClassBody -> result.addAll(ctx.typeParams)
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
return emptySet()
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseTypeParamList(): List<TypeDecl.TypeParam> {
|
||||||
|
if (cc.peekNextNonWhitespace().type != Token.Type.LT) return emptyList()
|
||||||
|
val typeParams = mutableListOf<TypeDecl.TypeParam>()
|
||||||
|
cc.nextNonWhitespace()
|
||||||
|
while (true) {
|
||||||
|
val varianceToken = cc.peekNextNonWhitespace()
|
||||||
|
val variance = when (varianceToken.value) {
|
||||||
|
"in" -> {
|
||||||
|
cc.nextNonWhitespace()
|
||||||
|
TypeDecl.Variance.In
|
||||||
|
}
|
||||||
|
"out" -> {
|
||||||
|
cc.nextNonWhitespace()
|
||||||
|
TypeDecl.Variance.Out
|
||||||
|
}
|
||||||
|
else -> TypeDecl.Variance.Invariant
|
||||||
|
}
|
||||||
|
val idTok = cc.requireToken(Token.Type.ID, "type parameter name expected")
|
||||||
|
var bound: TypeDecl? = null
|
||||||
|
var defaultType: TypeDecl? = null
|
||||||
|
if (cc.skipTokenOfType(Token.Type.COLON, isOptional = true)) {
|
||||||
|
bound = parseTypeExpressionWithMini().first
|
||||||
|
}
|
||||||
|
if (cc.skipTokenOfType(Token.Type.ASSIGN, isOptional = true)) {
|
||||||
|
defaultType = parseTypeExpressionWithMini().first
|
||||||
|
}
|
||||||
|
typeParams.add(TypeDecl.TypeParam(idTok.value, variance, bound, defaultType))
|
||||||
|
val sep = cc.nextNonWhitespace()
|
||||||
|
when (sep.type) {
|
||||||
|
Token.Type.COMMA -> continue
|
||||||
|
Token.Type.GT -> break
|
||||||
|
Token.Type.SHR -> {
|
||||||
|
cc.pushPendingGT()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
else -> sep.raiseSyntax("expected ',' or '>' in type parameter list")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeParams
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun lookupSlotLocation(name: String, includeModule: Boolean = true): SlotLocation? {
|
private fun lookupSlotLocation(name: String, includeModule: Boolean = true): SlotLocation? {
|
||||||
@ -3702,6 +3747,9 @@ class Compiler(
|
|||||||
resolutionSink?.declareSymbol(nameToken.value, SymbolKind.CLASS, isMutable = false, pos = nameToken.pos)
|
resolutionSink?.declareSymbol(nameToken.value, SymbolKind.CLASS, isMutable = false, pos = nameToken.pos)
|
||||||
return inCodeContext(CodeContext.ClassBody(nameToken.value, isExtern = isExtern)) {
|
return inCodeContext(CodeContext.ClassBody(nameToken.value, isExtern = isExtern)) {
|
||||||
val classCtx = codeContexts.lastOrNull() as? CodeContext.ClassBody
|
val classCtx = codeContexts.lastOrNull() as? CodeContext.ClassBody
|
||||||
|
val typeParamDecls = parseTypeParamList()
|
||||||
|
classCtx?.typeParamDecls = typeParamDecls
|
||||||
|
classCtx?.typeParams = typeParamDecls.map { it.name }.toSet()
|
||||||
val constructorArgsDeclaration =
|
val constructorArgsDeclaration =
|
||||||
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true))
|
||||||
parseArgsDeclaration(isClassDeclaration = true)
|
parseArgsDeclaration(isClassDeclaration = true)
|
||||||
@ -3731,15 +3779,19 @@ class Compiler(
|
|||||||
val baseSpecs = mutableListOf<BaseSpec>()
|
val baseSpecs = mutableListOf<BaseSpec>()
|
||||||
if (cc.skipTokenOfType(Token.Type.COLON, isOptional = true)) {
|
if (cc.skipTokenOfType(Token.Type.COLON, isOptional = true)) {
|
||||||
do {
|
do {
|
||||||
val baseId = cc.requireToken(Token.Type.ID, "base class name expected")
|
val (baseDecl, _) = parseSimpleTypeExpressionWithMini()
|
||||||
resolutionSink?.reference(baseId.value, baseId.pos)
|
val baseName = when (baseDecl) {
|
||||||
|
is TypeDecl.Simple -> baseDecl.name
|
||||||
|
is TypeDecl.Generic -> baseDecl.name
|
||||||
|
else -> throw ScriptError(cc.currentPos(), "base class name expected")
|
||||||
|
}
|
||||||
var argsList: List<ParsedArgument>? = null
|
var argsList: List<ParsedArgument>? = null
|
||||||
// Optional constructor args of the base — parse and ignore for now (MVP), just to consume tokens
|
// Optional constructor args of the base — parse and ignore for now (MVP), just to consume tokens
|
||||||
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true)) {
|
if (cc.skipTokenOfType(Token.Type.LPAREN, isOptional = true)) {
|
||||||
// Parse args without consuming any following block so that a class body can follow safely
|
// Parse args without consuming any following block so that a class body can follow safely
|
||||||
argsList = parseArgsNoTailBlock()
|
argsList = parseArgsNoTailBlock()
|
||||||
}
|
}
|
||||||
baseSpecs += BaseSpec(baseId.value, argsList)
|
baseSpecs += BaseSpec(baseName, argsList)
|
||||||
} while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true))
|
} while (cc.skipTokenOfType(Token.Type.COMMA, isOptional = true))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4360,24 +4412,8 @@ class Compiler(
|
|||||||
declareLocalName(extensionWrapperName, isMutable = false)
|
declareLocalName(extensionWrapperName, isMutable = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
val typeParams = mutableSetOf<String>()
|
val typeParamDecls = parseTypeParamList()
|
||||||
if (cc.peekNextNonWhitespace().type == Token.Type.LT) {
|
val typeParams = typeParamDecls.map { it.name }.toSet()
|
||||||
cc.nextNonWhitespace()
|
|
||||||
while (true) {
|
|
||||||
val idTok = cc.requireToken(Token.Type.ID, "type parameter name expected")
|
|
||||||
typeParams.add(idTok.value)
|
|
||||||
val sep = cc.nextNonWhitespace()
|
|
||||||
when (sep.type) {
|
|
||||||
Token.Type.COMMA -> continue
|
|
||||||
Token.Type.GT -> break
|
|
||||||
Token.Type.SHR -> {
|
|
||||||
cc.pushPendingGT()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
else -> sep.raiseSyntax("expected ',' or '>' in type parameter list")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val argsDeclaration: ArgsDeclaration =
|
val argsDeclaration: ArgsDeclaration =
|
||||||
if (cc.peekNextNonWhitespace().type == Token.Type.LPAREN) {
|
if (cc.peekNextNonWhitespace().type == Token.Type.LPAREN) {
|
||||||
@ -4441,7 +4477,8 @@ class Compiler(
|
|||||||
name,
|
name,
|
||||||
implicitThisMembers = implicitThisMembers,
|
implicitThisMembers = implicitThisMembers,
|
||||||
implicitThisTypeName = extTypeName,
|
implicitThisTypeName = extTypeName,
|
||||||
typeParams = typeParams
|
typeParams = typeParams,
|
||||||
|
typeParamDecls = typeParamDecls
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
cc.labels.add(name)
|
cc.labels.add(name)
|
||||||
|
|||||||
@ -22,6 +22,7 @@ package net.sergeych.lyng
|
|||||||
// this is highly experimental and subject to complete redesign
|
// this is highly experimental and subject to complete redesign
|
||||||
// very soon
|
// very soon
|
||||||
sealed class TypeDecl(val isNullable:Boolean = false) {
|
sealed class TypeDecl(val isNullable:Boolean = false) {
|
||||||
|
enum class Variance { In, Out, Invariant }
|
||||||
// ??
|
// ??
|
||||||
data class Function(
|
data class Function(
|
||||||
val receiver: TypeDecl?,
|
val receiver: TypeDecl?,
|
||||||
@ -30,6 +31,12 @@ sealed class TypeDecl(val isNullable:Boolean = false) {
|
|||||||
val nullable: Boolean = false
|
val nullable: Boolean = false
|
||||||
) : TypeDecl(nullable)
|
) : TypeDecl(nullable)
|
||||||
data class TypeVar(val name: String, val nullable: Boolean = false) : TypeDecl(nullable)
|
data class TypeVar(val name: String, val nullable: Boolean = false) : TypeDecl(nullable)
|
||||||
|
data class TypeParam(
|
||||||
|
val name: String,
|
||||||
|
val variance: Variance = Variance.Invariant,
|
||||||
|
val bound: TypeDecl? = null,
|
||||||
|
val defaultType: TypeDecl? = null
|
||||||
|
)
|
||||||
object TypeAny : TypeDecl()
|
object TypeAny : TypeDecl()
|
||||||
object TypeNullableAny : TypeDecl(true)
|
object TypeNullableAny : TypeDecl(true)
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package lyng.stdlib
|
package lyng.stdlib
|
||||||
|
|
||||||
// desired type: FlowBuilder.()->void (function types not yet supported in type grammar)
|
extern fun flow(builder: FlowBuilder.()->Void): Flow
|
||||||
extern fun flow(builder)
|
|
||||||
|
|
||||||
/* Built-in exception type. */
|
/* Built-in exception type. */
|
||||||
extern class Exception
|
extern class Exception
|
||||||
@ -10,10 +9,10 @@ extern class NotImplementedException
|
|||||||
extern class Delegate
|
extern class Delegate
|
||||||
|
|
||||||
// Built-in math helpers (implemented in host runtime).
|
// Built-in math helpers (implemented in host runtime).
|
||||||
extern fun abs(x)
|
extern fun abs(x: Object): Real
|
||||||
extern fun ln(x)
|
extern fun ln(x: Object): Real
|
||||||
extern fun pow(x, y)
|
extern fun pow(x: Object, y: Object): Real
|
||||||
extern fun sqrt(x)
|
extern fun sqrt(x: Object): Real
|
||||||
|
|
||||||
// Last regex match result, updated by =~ / !~.
|
// Last regex match result, updated by =~ / !~.
|
||||||
var $~ = null
|
var $~ = null
|
||||||
@ -22,7 +21,7 @@ var $~ = null
|
|||||||
Wrap a builder into a zero-argument thunk that computes once and caches the result.
|
Wrap a builder into a zero-argument thunk that computes once and caches the result.
|
||||||
The first call invokes builder() and stores the value; subsequent calls return the cached value.
|
The first call invokes builder() and stores the value; subsequent calls return the cached value.
|
||||||
*/
|
*/
|
||||||
fun cached(builder) {
|
fun cached<T>(builder: ()->T): ()->T {
|
||||||
var calculated = false
|
var calculated = false
|
||||||
var value = null
|
var value = null
|
||||||
{
|
{
|
||||||
@ -30,13 +29,13 @@ fun cached(builder) {
|
|||||||
value = builder()
|
value = builder()
|
||||||
calculated = true
|
calculated = true
|
||||||
}
|
}
|
||||||
value
|
value as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Filter elements of this iterable using the provided predicate and provide a flow
|
/* Filter elements of this iterable using the provided predicate and provide a flow
|
||||||
of results. Coudl be used to map infinte flows, etc.
|
of results. Coudl be used to map infinte flows, etc.
|
||||||
*/
|
*/
|
||||||
fun Iterable.filterFlow(predicate): Flow {
|
fun Iterable.filterFlow<T>(predicate: (T)->Bool): Flow<T> {
|
||||||
val list = this
|
val list = this
|
||||||
flow {
|
flow {
|
||||||
for( item in list ) {
|
for( item in list ) {
|
||||||
@ -50,8 +49,8 @@ fun Iterable.filterFlow(predicate): Flow {
|
|||||||
/*
|
/*
|
||||||
Filter this iterable and return List of elements
|
Filter this iterable and return List of elements
|
||||||
*/
|
*/
|
||||||
fun Iterable.filter(predicate) {
|
fun Iterable.filter<T>(predicate: (T)->Bool): List<T> {
|
||||||
var result: List = List()
|
var result: List<T> = List()
|
||||||
for( item in this ) if( predicate(item) ) result += item
|
for( item in this ) if( predicate(item) ) result += item
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -59,7 +58,7 @@ fun Iterable.filter(predicate) {
|
|||||||
/*
|
/*
|
||||||
Count all items in this iterable for which predicate returns true
|
Count all items in this iterable for which predicate returns true
|
||||||
*/
|
*/
|
||||||
fun Iterable.count(predicate): Int {
|
fun Iterable.count<T>(predicate: (T)->Bool): Int {
|
||||||
var hits = 0
|
var hits = 0
|
||||||
this.forEach {
|
this.forEach {
|
||||||
if( predicate(it) ) hits++
|
if( predicate(it) ) hits++
|
||||||
@ -70,24 +69,24 @@ fun Iterable.count(predicate): Int {
|
|||||||
filter out all null elements from this collection (Iterable); flow of
|
filter out all null elements from this collection (Iterable); flow of
|
||||||
non-null elements is returned
|
non-null elements is returned
|
||||||
*/
|
*/
|
||||||
fun Iterable.filterFlowNotNull(): Flow {
|
fun Iterable.filterFlowNotNull<T>(): Flow<T> {
|
||||||
filterFlow { it != null }
|
filterFlow { it != null }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Filter non-null elements and collect them into a List
|
/* Filter non-null elements and collect them into a List
|
||||||
*/
|
*/
|
||||||
fun Iterable.filterNotNull(): List {
|
fun Iterable.filterNotNull<T>(): List<T> {
|
||||||
filter { it != null }
|
filter { it != null }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip the first N elements of this iterable. */
|
/* Skip the first N elements of this iterable. */
|
||||||
fun Iterable.drop(n) {
|
fun Iterable.drop<T>(n: Int): List<T> {
|
||||||
var cnt = 0
|
var cnt = 0
|
||||||
filter { cnt++ >= n }
|
filter { cnt++ >= n }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the first element or throw if the iterable is empty. */
|
/* Return the first element or throw if the iterable is empty. */
|
||||||
val Iterable.first get() {
|
val Iterable.first: Object get() {
|
||||||
val i: Iterator = iterator()
|
val i: Iterator = iterator()
|
||||||
if( !i.hasNext() ) throw NoSuchElementException()
|
if( !i.hasNext() ) throw NoSuchElementException()
|
||||||
i.next().also { i.cancelIteration() }
|
i.next().also { i.cancelIteration() }
|
||||||
@ -97,7 +96,7 @@ val Iterable.first get() {
|
|||||||
Return the first element that matches the predicate or throws
|
Return the first element that matches the predicate or throws
|
||||||
NuSuchElementException
|
NuSuchElementException
|
||||||
*/
|
*/
|
||||||
fun Iterable.findFirst(predicate) {
|
fun Iterable.findFirst<T>(predicate: (T)->Bool): T {
|
||||||
for( x in this ) {
|
for( x in this ) {
|
||||||
if( predicate(x) )
|
if( predicate(x) )
|
||||||
break x
|
break x
|
||||||
@ -108,7 +107,7 @@ fun Iterable.findFirst(predicate) {
|
|||||||
/*
|
/*
|
||||||
return the first element matching the predicate or null
|
return the first element matching the predicate or null
|
||||||
*/
|
*/
|
||||||
fun Iterable.findFirstOrNull(predicate) {
|
fun Iterable.findFirstOrNull<T>(predicate: (T)->Bool): T? {
|
||||||
for( x in this ) {
|
for( x in this ) {
|
||||||
if( predicate(x) )
|
if( predicate(x) )
|
||||||
break x
|
break x
|
||||||
@ -118,7 +117,7 @@ fun Iterable.findFirstOrNull(predicate) {
|
|||||||
|
|
||||||
|
|
||||||
/* Return the last element or throw if the iterable is empty. */
|
/* Return the last element or throw if the iterable is empty. */
|
||||||
val Iterable.last get() {
|
val Iterable.last: Object get() {
|
||||||
var found = false
|
var found = false
|
||||||
var element = null
|
var element = null
|
||||||
for( i in this ) {
|
for( i in this ) {
|
||||||
@ -130,7 +129,7 @@ val Iterable.last get() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Emit all but the last N elements of this iterable. */
|
/* Emit all but the last N elements of this iterable. */
|
||||||
fun Iterable.dropLast(n) {
|
fun Iterable.dropLast<T>(n: Int): Flow<T> {
|
||||||
val list = this
|
val list = this
|
||||||
val buffer = RingBuffer(n)
|
val buffer = RingBuffer(n)
|
||||||
flow {
|
flow {
|
||||||
@ -143,17 +142,17 @@ fun Iterable.dropLast(n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return the last N elements of this iterable as a buffer/list. */
|
/* Return the last N elements of this iterable as a buffer/list. */
|
||||||
fun Iterable.takeLast(n) {
|
fun Iterable.takeLast<T>(n: Int): RingBuffer<T> {
|
||||||
val buffer = RingBuffer(n)
|
val buffer: RingBuffer<T> = RingBuffer(n)
|
||||||
for( item in this ) buffer += item
|
for( item in this ) buffer += item
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Join elements into a string with a separator (separator parameter) and optional transformer. */
|
/* Join elements into a string with a separator (separator parameter) and optional transformer. */
|
||||||
fun Iterable.joinToString(separator=" ", transformer=null) {
|
fun Iterable.joinToString<T>(separator: String=" ", transformer: (T)->Object = { it }): String {
|
||||||
var result = null
|
var result = null
|
||||||
for( part in this ) {
|
for( part in this ) {
|
||||||
val transformed = transformer?(part)?.toString() ?: part.toString()
|
val transformed = transformer(part).toString()
|
||||||
if( result == null ) result = transformed
|
if( result == null ) result = transformed
|
||||||
else result += separator + transformed
|
else result += separator + transformed
|
||||||
}
|
}
|
||||||
@ -161,7 +160,7 @@ fun Iterable.joinToString(separator=" ", transformer=null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if any element matches the predicate. */
|
/* Return true if any element matches the predicate. */
|
||||||
fun Iterable.any(predicate): Bool {
|
fun Iterable.any<T>(predicate: (T)->Bool): Bool {
|
||||||
for( i in this ) {
|
for( i in this ) {
|
||||||
if( predicate(i) )
|
if( predicate(i) )
|
||||||
break true
|
break true
|
||||||
@ -169,12 +168,12 @@ fun Iterable.any(predicate): Bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if all elements match the predicate. */
|
/* Return true if all elements match the predicate. */
|
||||||
fun Iterable.all(predicate): Bool {
|
fun Iterable.all<T>(predicate: (T)->Bool): Bool {
|
||||||
!any { !predicate(it) }
|
!any { !predicate(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sum all elements; returns null for empty collections. */
|
/* Sum all elements; returns null for empty collections. */
|
||||||
fun Iterable.sum() {
|
fun Iterable.sum<T>(): T? {
|
||||||
val i: Iterator = iterator()
|
val i: Iterator = iterator()
|
||||||
if( i.hasNext() ) {
|
if( i.hasNext() ) {
|
||||||
var result = i.next()
|
var result = i.next()
|
||||||
@ -185,7 +184,7 @@ fun Iterable.sum() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Sum mapped values of elements; returns null for empty collections. */
|
/* Sum mapped values of elements; returns null for empty collections. */
|
||||||
fun Iterable.sumOf(f) {
|
fun Iterable.sumOf<T,R>(f: (T)->R): R? {
|
||||||
val i: Iterator = iterator()
|
val i: Iterator = iterator()
|
||||||
if( i.hasNext() ) {
|
if( i.hasNext() ) {
|
||||||
var result = f(i.next())
|
var result = f(i.next())
|
||||||
@ -196,7 +195,7 @@ fun Iterable.sumOf(f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Minimum value of the given function applied to elements of the collection. */
|
/* Minimum value of the given function applied to elements of the collection. */
|
||||||
fun Iterable.minOf( lambda ) {
|
fun Iterable.minOf<T,R>(lambda: (T)->R): R {
|
||||||
val i: Iterator = iterator()
|
val i: Iterator = iterator()
|
||||||
var minimum = lambda( i.next() )
|
var minimum = lambda( i.next() )
|
||||||
while( i.hasNext() ) {
|
while( i.hasNext() ) {
|
||||||
@ -207,7 +206,7 @@ fun Iterable.minOf( lambda ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Maximum value of the given function applied to elements of the collection. */
|
/* Maximum value of the given function applied to elements of the collection. */
|
||||||
fun Iterable.maxOf( lambda ) {
|
fun Iterable.maxOf<T,R>(lambda: (T)->R): R {
|
||||||
val i: Iterator = iterator()
|
val i: Iterator = iterator()
|
||||||
var maximum = lambda( i.next() )
|
var maximum = lambda( i.next() )
|
||||||
while( i.hasNext() ) {
|
while( i.hasNext() ) {
|
||||||
@ -218,18 +217,18 @@ fun Iterable.maxOf( lambda ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Return elements sorted by natural order. */
|
/* Return elements sorted by natural order. */
|
||||||
fun Iterable.sorted() {
|
fun Iterable.sorted<T>(): List<T> {
|
||||||
sortedWith { a, b -> a <=> b }
|
sortedWith { a, b -> a <=> b }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return elements sorted by the key selector. */
|
/* Return elements sorted by the key selector. */
|
||||||
fun Iterable.sortedBy(predicate) {
|
fun Iterable.sortedBy<T,R>(predicate: (T)->R): List<T> {
|
||||||
sortedWith { a, b -> predicate(a) <=> predicate(b) }
|
sortedWith { a, b -> predicate(a) <=> predicate(b) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a shuffled copy of the iterable as a list. */
|
/* Return a shuffled copy of the iterable as a list. */
|
||||||
fun Iterable.shuffled() {
|
fun Iterable.shuffled<T>(): List<T> {
|
||||||
val list: List = toList()
|
val list: List<T> = toList()
|
||||||
list.shuffle()
|
list.shuffle()
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
@ -238,8 +237,8 @@ fun Iterable.shuffled() {
|
|||||||
Returns a single list of all elements from all collections in the given collection.
|
Returns a single list of all elements from all collections in the given collection.
|
||||||
@return List
|
@return List
|
||||||
*/
|
*/
|
||||||
fun Iterable.flatten() {
|
fun Iterable.flatten<T>(): List<T> {
|
||||||
var result: List = List()
|
var result: List<T> = List()
|
||||||
forEach { i ->
|
forEach { i ->
|
||||||
i.forEach { result += it }
|
i.forEach { result += it }
|
||||||
}
|
}
|
||||||
@ -250,8 +249,8 @@ fun Iterable.flatten() {
|
|||||||
Returns a single list of all elements yielded from results of transform function being
|
Returns a single list of all elements yielded from results of transform function being
|
||||||
invoked on each element of original collection.
|
invoked on each element of original collection.
|
||||||
*/
|
*/
|
||||||
fun Iterable.flatMap(transform): List {
|
fun Iterable.flatMap<T,R>(transform: (T)->Iterable<R>): List<R> {
|
||||||
val mapped: List = map(transform)
|
val mapped: List<Iterable<R>> = map(transform)
|
||||||
mapped.flatten()
|
mapped.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,26 +267,26 @@ override fun List.toString() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Sort list in-place by key selector. */
|
/* Sort list in-place by key selector. */
|
||||||
fun List.sortBy(predicate) {
|
fun List.sortBy<T,R>(predicate: (T)->R): Void {
|
||||||
sortWith { a, b -> predicate(a) <=> predicate(b) }
|
sortWith { a, b -> predicate(a) <=> predicate(b) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort list in-place by natural order. */
|
/* Sort list in-place by natural order. */
|
||||||
fun List.sort() {
|
fun List.sort<T>(): Void {
|
||||||
sortWith { a, b -> a <=> b }
|
sortWith { a, b -> a <=> b }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print this exception and its stack trace to standard output. */
|
/* Print this exception and its stack trace to standard output. */
|
||||||
fun Exception.printStackTrace() {
|
fun Exception.printStackTrace(): Void {
|
||||||
println(this)
|
println(this)
|
||||||
for( entry in stackTrace )
|
for( entry in stackTrace )
|
||||||
println("\tat "+entry.toString())
|
println("\tat "+entry.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compile this string into a regular expression. */
|
/* Compile this string into a regular expression. */
|
||||||
val String.re get() = Regex(this)
|
val String.re: Regex get() = Regex(this)
|
||||||
|
|
||||||
fun TODO(message=null) {
|
fun TODO(message: Object?=null): Void {
|
||||||
throw "not implemented"
|
throw "not implemented"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,21 +305,21 @@ enum DelegateAccess {
|
|||||||
Implementing this interface is optional as Lyng uses dynamic dispatch,
|
Implementing this interface is optional as Lyng uses dynamic dispatch,
|
||||||
but it is recommended for documentation and clarity.
|
but it is recommended for documentation and clarity.
|
||||||
*/
|
*/
|
||||||
interface Delegate {
|
interface Delegate<T,ThisRefType=Void> {
|
||||||
/* Called when a delegated 'val' or 'var' is read. */
|
/* Called when a delegated 'val' or 'var' is read. */
|
||||||
fun getValue(thisRef, name) = TODO("delegate getter is not implemented")
|
fun getValue(thisRef: ThisRefType, name: String): T = TODO("delegate getter is not implemented")
|
||||||
|
|
||||||
/* Called when a delegated 'var' is written. */
|
/* Called when a delegated 'var' is written. */
|
||||||
fun setValue(thisRef, name, newValue) = TODO("delegate setter is not implemented")
|
fun setValue(thisRef: ThisRefType, name: String, newValue: T): Void = TODO("delegate setter is not implemented")
|
||||||
|
|
||||||
/* Called when a delegated function is invoked. */
|
/* Called when a delegated function is invoked. */
|
||||||
fun invoke(thisRef, name, args...) = TODO("delegate invoke is not implemented")
|
fun invoke(thisRef: ThisRefType, name: String, args...): Object = TODO("delegate invoke is not implemented")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Called once during initialization to configure or validate the delegate.
|
Called once during initialization to configure or validate the delegate.
|
||||||
Should return the delegate object to be used (usually 'this').
|
Should return the delegate object to be used (usually 'this').
|
||||||
*/
|
*/
|
||||||
fun bind(name, access, thisRef) = this
|
fun bind(name: String, access: DelegateAccess, thisRef: ThisRefType): Object = this
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -338,19 +337,19 @@ fun with<T,R>(self: T, block: T.()->R): R {
|
|||||||
The provided creator lambda is called once on the first access to compute the value.
|
The provided creator lambda is called once on the first access to compute the value.
|
||||||
Can only be used with 'val' properties.
|
Can only be used with 'val' properties.
|
||||||
*/
|
*/
|
||||||
class lazy(creatorParam) : Delegate {
|
class lazy<T>(creatorParam: Object.()->T) : Delegate<T,Object> {
|
||||||
private val creator = creatorParam
|
private val creator: Object.()->T = creatorParam
|
||||||
private var value = Unset
|
private var value = Unset
|
||||||
|
|
||||||
override fun bind(name, access, thisRef) {
|
override fun bind(name: String, access: DelegateAccess, thisRef: Object): Object {
|
||||||
if (access.toString() != "DelegateAccess.Val") throw "lazy delegate can only be used with 'val'"
|
if (access.toString() != "DelegateAccess.Val") throw "lazy delegate can only be used with 'val'"
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getValue(thisRef, name) {
|
override fun getValue(thisRef: Object, name: String): T {
|
||||||
if (value == Unset)
|
if (value == Unset)
|
||||||
value = with(thisRef,creator)
|
value = with(thisRef,creator)
|
||||||
value
|
value as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -203,7 +203,12 @@ square("3.14")
|
|||||||
|
|
||||||
- Generics runtime model: Are type params reified via hidden Class args always, or only when used (T::class, T is ...)? How does this interact with Kotlin interop?
|
- Generics runtime model: Are type params reified via hidden Class args always, or only when used (T::class, T is ...)? How does this interact with Kotlin interop?
|
||||||
|
|
||||||
I think we can omit if not used. For kotlin interop: if the class has at least one `extern` symbol, that means native implementation, we always include type parameters, to kotlin implementation can rely on it.
|
Type params are erased by default. Hidden `Class` args are only injected when a type parameter is used in a reified way (`T::class`, `T is`, `is T`, `as T`) or when the class has at least one `extern` symbol (so host implementations can rely on them). Otherwise `T` is compile-time only and runtime uses `Object`.
|
||||||
|
|
||||||
|
- Variance syntax:
|
||||||
|
- Declaration-site only, Kotlin-style: `out` (covariant) and `in` (contravariant).
|
||||||
|
- Example: `class Box<out T>`, `class Sink<in T>`.
|
||||||
|
- Bounds remain `T: A & B` or `T: A | B`.
|
||||||
|
|
||||||
- Member access rules: If a variable is Object (dynamic), is member access a compile-time error, or allowed with fallback (which we are trying to remove)? If error, do we require explicit cast first?
|
- Member access rules: If a variable is Object (dynamic), is member access a compile-time error, or allowed with fallback (which we are trying to remove)? If error, do we require explicit cast first?
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user