fixed few bugs in compiler and plugin
This commit is contained in:
parent
37d093817e
commit
e447c778ed
@ -88,11 +88,13 @@ class LyngExternalAnnotator : ExternalAnnotator<LyngExternalAnnotator.Input, Lyn
|
|||||||
// Imports: each segment as namespace/path
|
// Imports: each segment as namespace/path
|
||||||
mini?.imports?.forEach { imp ->
|
mini?.imports?.forEach { imp ->
|
||||||
imp.segments.forEach { seg ->
|
imp.segments.forEach { seg ->
|
||||||
|
if (seg.range.start.source === analysis.source && seg.range.end.source === analysis.source) {
|
||||||
val start = analysis.source.offsetOf(seg.range.start)
|
val start = analysis.source.offsetOf(seg.range.start)
|
||||||
val end = analysis.source.offsetOf(seg.range.end)
|
val end = analysis.source.offsetOf(seg.range.end)
|
||||||
putRange(start, end, LyngHighlighterColors.NAMESPACE)
|
putRange(start, end, LyngHighlighterColors.NAMESPACE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add annotation/label coloring using token highlighter
|
// Add annotation/label coloring using token highlighter
|
||||||
run {
|
run {
|
||||||
|
|||||||
@ -35,7 +35,7 @@ class LyngLexer : LexerBase() {
|
|||||||
"fun", "val", "var", "class", "interface", "type", "import", "as",
|
"fun", "val", "var", "class", "interface", "type", "import", "as",
|
||||||
"abstract", "closed", "override", "static", "extern", "open", "private", "protected",
|
"abstract", "closed", "override", "static", "extern", "open", "private", "protected",
|
||||||
"if", "else", "for", "while", "return", "true", "false", "null",
|
"if", "else", "for", "while", "return", "true", "false", "null",
|
||||||
"when", "in", "is", "break", "continue", "try", "catch", "finally",
|
"when", "in", "is", "break", "continue", "try", "catch", "finally", "void",
|
||||||
"get", "set", "object", "enum", "init", "by", "step", "property", "constructor"
|
"get", "set", "object", "enum", "init", "by", "step", "property", "constructor"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -26,23 +26,16 @@ import com.intellij.psi.search.FilenameIndex
|
|||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import net.sergeych.lyng.binding.BindingSnapshot
|
import net.sergeych.lyng.binding.BindingSnapshot
|
||||||
import net.sergeych.lyng.miniast.BuiltinDocRegistry
|
|
||||||
import net.sergeych.lyng.miniast.DocLookupUtils
|
|
||||||
import net.sergeych.lyng.miniast.MiniEnumDecl
|
|
||||||
import net.sergeych.lyng.miniast.MiniRange
|
|
||||||
import net.sergeych.lyng.miniast.MiniScript
|
|
||||||
import net.sergeych.lyng.tools.IdeLenientImportProvider
|
|
||||||
import net.sergeych.lyng.tools.LyngAnalysisRequest
|
|
||||||
import net.sergeych.lyng.tools.LyngAnalysisResult
|
|
||||||
import net.sergeych.lyng.tools.LyngDiagnostic
|
|
||||||
import net.sergeych.lyng.tools.LyngLanguageTools
|
|
||||||
import net.sergeych.lyng.idea.LyngFileType
|
import net.sergeych.lyng.idea.LyngFileType
|
||||||
|
import net.sergeych.lyng.miniast.*
|
||||||
|
import net.sergeych.lyng.tools.*
|
||||||
|
|
||||||
object LyngAstManager {
|
object LyngAstManager {
|
||||||
private val MINI_KEY = Key.create<MiniScript>("lyng.mini.cache")
|
private val MINI_KEY = Key.create<MiniScript>("lyng.mini.cache")
|
||||||
private val BINDING_KEY = Key.create<BindingSnapshot>("lyng.binding.cache")
|
private val BINDING_KEY = Key.create<BindingSnapshot>("lyng.binding.cache")
|
||||||
private val STAMP_KEY = Key.create<Long>("lyng.mini.cache.stamp")
|
private val STAMP_KEY = Key.create<Long>("lyng.mini.cache.stamp")
|
||||||
private val ANALYSIS_KEY = Key.create<LyngAnalysisResult>("lyng.analysis.cache")
|
private val ANALYSIS_KEY = Key.create<LyngAnalysisResult>("lyng.analysis.cache")
|
||||||
|
private val implicitBuiltinNames = setOf("void")
|
||||||
|
|
||||||
fun getMiniAst(file: PsiFile): MiniScript? = runReadAction {
|
fun getMiniAst(file: PsiFile): MiniScript? = runReadAction {
|
||||||
getAnalysis(file)?.mini
|
getAnalysis(file)?.mini
|
||||||
@ -217,7 +210,7 @@ object LyngAstManager {
|
|||||||
val msg = diag.message
|
val msg = diag.message
|
||||||
if (msg.startsWith("unresolved name: ")) {
|
if (msg.startsWith("unresolved name: ")) {
|
||||||
val name = msg.removePrefix("unresolved name: ").trim()
|
val name = msg.removePrefix("unresolved name: ").trim()
|
||||||
name in declaredTopLevel || name in builtinTopLevel
|
name in declaredTopLevel || name in builtinTopLevel || name in implicitBuiltinNames
|
||||||
} else if (msg.startsWith("unresolved member: ")) {
|
} else if (msg.startsWith("unresolved member: ")) {
|
||||||
val name = msg.removePrefix("unresolved member: ").trim()
|
val name = msg.removePrefix("unresolved member: ").trim()
|
||||||
val range = diag.range
|
val range = diag.range
|
||||||
|
|||||||
@ -124,4 +124,16 @@ class LyngDefinitionFilesTest : BasePlatformTestCase() {
|
|||||||
assertTrue("Should not report unresolved name for Declared", messages.none { it.contains("unresolved name: Declared") })
|
assertTrue("Should not report unresolved name for Declared", messages.none { it.contains("unresolved name: Declared") })
|
||||||
assertTrue("Should not report unresolved member for greet", messages.none { it.contains("unresolved member: greet") })
|
assertTrue("Should not report unresolved member for greet", messages.none { it.contains("unresolved member: greet") })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun test_DiagnosticsDoNotReportVoidAsUnresolvedName() {
|
||||||
|
val code = """
|
||||||
|
fun f(): void {
|
||||||
|
return void
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
myFixture.configureByText("main.lyng", code)
|
||||||
|
val analysis = LyngAstManager.getAnalysis(myFixture.file)
|
||||||
|
val messages = analysis?.diagnostics?.map { it.message } ?: emptyList()
|
||||||
|
assertTrue("Should not report unresolved name for void, got=$messages", messages.none { it.contains("unresolved name: void") })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,6 +176,8 @@ class Compiler(
|
|||||||
private val lambdaCaptureEntriesByRef: MutableMap<ValueFnRef, List<net.sergeych.lyng.bytecode.LambdaCaptureEntry>> =
|
private val lambdaCaptureEntriesByRef: MutableMap<ValueFnRef, List<net.sergeych.lyng.bytecode.LambdaCaptureEntry>> =
|
||||||
mutableMapOf()
|
mutableMapOf()
|
||||||
private val classFieldTypesByName: MutableMap<String, MutableMap<String, ObjClass>> = mutableMapOf()
|
private val classFieldTypesByName: MutableMap<String, MutableMap<String, ObjClass>> = mutableMapOf()
|
||||||
|
private val classMethodReturnTypeByName: MutableMap<String, MutableMap<String, ObjClass>> = mutableMapOf()
|
||||||
|
private val classMethodReturnTypeDeclByName: MutableMap<String, MutableMap<String, TypeDecl>> = mutableMapOf()
|
||||||
private val classScopeMembersByClassName: MutableMap<String, MutableSet<String>> = mutableMapOf()
|
private val classScopeMembersByClassName: MutableMap<String, MutableSet<String>> = mutableMapOf()
|
||||||
private val classScopeCallableMembersByClassName: MutableMap<String, MutableSet<String>> = mutableMapOf()
|
private val classScopeCallableMembersByClassName: MutableMap<String, MutableSet<String>> = mutableMapOf()
|
||||||
private val encodedPayloadTypeByScopeId: MutableMap<Int, MutableMap<Int, ObjClass>> = mutableMapOf()
|
private val encodedPayloadTypeByScopeId: MutableMap<Int, MutableMap<Int, ObjClass>> = mutableMapOf()
|
||||||
@ -2614,7 +2616,34 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Token.Type.NOT -> {
|
Token.Type.NOT -> {
|
||||||
if (operand != null) throw ScriptError(t.pos, "unexpected operator not '!' ")
|
if (operand != null) {
|
||||||
|
val save = cc.savePos()
|
||||||
|
val next = cc.next()
|
||||||
|
if (next.type == Token.Type.NOT) {
|
||||||
|
val operandRef = operand
|
||||||
|
val receiverClass = resolveReceiverClassForMember(operandRef)
|
||||||
|
val inferredType = resolveReceiverTypeDecl(operandRef)
|
||||||
|
?: receiverClass?.let { TypeDecl.Simple(it.className, false) }
|
||||||
|
if (inferredType == null) {
|
||||||
|
operand = operandRef
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (inferredType == TypeDecl.TypeAny || inferredType == TypeDecl.TypeNullableAny) {
|
||||||
|
operand = operandRef
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val nonNullType = makeTypeDeclNonNullable(inferredType)
|
||||||
|
operand = CastRef(
|
||||||
|
operandRef,
|
||||||
|
TypeDeclRef(nonNullType, t.pos),
|
||||||
|
isNullable = false,
|
||||||
|
atPos = t.pos
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cc.restorePos(save)
|
||||||
|
throw ScriptError(t.pos, "unexpected operator not '!' ")
|
||||||
|
}
|
||||||
val op = parseTerm() ?: throw ScriptError(t.pos, "Expecting expression")
|
val op = parseTerm() ?: throw ScriptError(t.pos, "Expecting expression")
|
||||||
operand = UnaryOpRef(UnaryOp.NOT, op)
|
operand = UnaryOpRef(UnaryOp.NOT, op)
|
||||||
}
|
}
|
||||||
@ -3821,6 +3850,21 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun makeTypeDeclNonNullable(type: TypeDecl): TypeDecl {
|
||||||
|
if (!type.isNullable) return type
|
||||||
|
return when (type) {
|
||||||
|
TypeDecl.TypeAny -> type
|
||||||
|
TypeDecl.TypeNullableAny -> TypeDecl.TypeAny
|
||||||
|
is TypeDecl.Function -> type.copy(nullable = false)
|
||||||
|
is TypeDecl.Ellipsis -> type.copy(nullable = false)
|
||||||
|
is TypeDecl.TypeVar -> type.copy(nullable = false)
|
||||||
|
is TypeDecl.Union -> type.copy(nullable = false)
|
||||||
|
is TypeDecl.Intersection -> type.copy(nullable = false)
|
||||||
|
is TypeDecl.Simple -> TypeDecl.Simple(type.name, false)
|
||||||
|
is TypeDecl.Generic -> TypeDecl.Generic(type.name, type.args, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun makeMiniTypeNullable(type: MiniTypeRef): MiniTypeRef {
|
private fun makeMiniTypeNullable(type: MiniTypeRef): MiniTypeRef {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
is MiniTypeName -> type.copy(nullable = true)
|
is MiniTypeName -> type.copy(nullable = true)
|
||||||
@ -4491,6 +4535,48 @@ class Compiler(
|
|||||||
is TypeDecl.Intersection -> "I:${type.options.joinToString("&") { typeDeclKey(it) }}"
|
is TypeDecl.Intersection -> "I:${type.options.joinToString("&") { typeDeclKey(it) }}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun classMethodReturnTypeDecl(targetClass: ObjClass?, name: String): TypeDecl? {
|
||||||
|
if (targetClass == null) return null
|
||||||
|
if (targetClass == ObjDynamic.type) return TypeDecl.TypeAny
|
||||||
|
val member = targetClass.getInstanceMemberOrNull(name, includeAbstract = true)
|
||||||
|
val declaringName = member?.declaringClass?.className
|
||||||
|
if (declaringName != null) {
|
||||||
|
classMethodReturnTypeDeclByName[declaringName]?.get(name)?.let { return it }
|
||||||
|
classMethodReturnTypeByName[declaringName]?.get(name)?.let {
|
||||||
|
return TypeDecl.Simple(it.className, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
classMethodReturnTypeDeclByName[targetClass.className]?.get(name)?.let { return it }
|
||||||
|
classMethodReturnTypeByName[targetClass.className]?.get(name)?.let {
|
||||||
|
return TypeDecl.Simple(it.className, false)
|
||||||
|
}
|
||||||
|
member?.typeDecl?.let { declaredType ->
|
||||||
|
if (declaredType is TypeDecl.Function) return declaredType.returnType
|
||||||
|
return declaredType
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun classMethodReturnClass(targetClass: ObjClass?, name: String): ObjClass? {
|
||||||
|
if (targetClass == null) return null
|
||||||
|
if (targetClass == ObjDynamic.type) return ObjDynamic.type
|
||||||
|
classMethodReturnTypeDecl(targetClass, name)?.let { declared ->
|
||||||
|
resolveTypeDeclObjClass(declared)?.let { return it }
|
||||||
|
if (declared is TypeDecl.TypeVar) return Obj.rootObjectType
|
||||||
|
}
|
||||||
|
val member = targetClass.getInstanceMemberOrNull(name, includeAbstract = true)
|
||||||
|
val declaringName = member?.declaringClass?.className
|
||||||
|
if (declaringName != null) {
|
||||||
|
classMethodReturnTypeByName[declaringName]?.get(name)?.let { return it }
|
||||||
|
}
|
||||||
|
classMethodReturnTypeByName[targetClass.className]?.get(name)?.let { return it }
|
||||||
|
val declaredType = member?.typeDecl
|
||||||
|
if (declaredType is TypeDecl.Function) {
|
||||||
|
resolveTypeDeclObjClass(declaredType.returnType)?.let { return it }
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
private fun inferObjClassFromRef(ref: ObjRef): ObjClass? = when (ref) {
|
private fun inferObjClassFromRef(ref: ObjRef): ObjClass? = when (ref) {
|
||||||
is ConstRef -> ref.constValue as? ObjClass ?: ref.constValue.objClass
|
is ConstRef -> ref.constValue as? ObjClass ?: ref.constValue.objClass
|
||||||
is LocalVarRef -> nameObjClass[ref.name] ?: resolveClassByName(ref.name)
|
is LocalVarRef -> nameObjClass[ref.name] ?: resolveClassByName(ref.name)
|
||||||
@ -4511,6 +4597,11 @@ class Compiler(
|
|||||||
is RangeRef -> ObjRange.type
|
is RangeRef -> ObjRange.type
|
||||||
is ClassOperatorRef -> ObjClassType
|
is ClassOperatorRef -> ObjClassType
|
||||||
is CastRef -> resolveTypeRefClass(ref.castTypeRef())
|
is CastRef -> resolveTypeRefClass(ref.castTypeRef())
|
||||||
|
is IndexRef -> {
|
||||||
|
val targetClass = resolveReceiverClassForMember(ref.targetRef)
|
||||||
|
classMethodReturnClass(targetClass, "getAt")
|
||||||
|
?: inferFieldReturnClass(targetClass, "getAt")
|
||||||
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4547,6 +4638,12 @@ class Compiler(
|
|||||||
else -> TypeDecl.TypeVar("${typeDeclName(targetDecl)}.${ref.name}", false)
|
else -> TypeDecl.TypeVar("${typeDeclName(targetDecl)}.${ref.name}", false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is IndexRef -> {
|
||||||
|
val targetDecl = resolveReceiverTypeDecl(ref.targetRef)
|
||||||
|
inferMethodCallReturnTypeDecl("getAt", targetDecl)?.let { return it }
|
||||||
|
val targetClass = resolveReceiverClassForMember(ref.targetRef)
|
||||||
|
classMethodReturnTypeDecl(targetClass, "getAt")
|
||||||
|
}
|
||||||
is MethodCallRef -> methodReturnTypeDeclByRef[ref]
|
is MethodCallRef -> methodReturnTypeDeclByRef[ref]
|
||||||
is CallRef -> callReturnTypeDeclByRef[ref]
|
is CallRef -> callReturnTypeDeclByRef[ref]
|
||||||
is StatementRef -> (ref.statement as? ExpressionStatement)?.let { resolveReceiverTypeDecl(it.ref) }
|
is StatementRef -> (ref.statement as? ExpressionStatement)?.let { resolveReceiverTypeDecl(it.ref) }
|
||||||
@ -4616,6 +4713,12 @@ class Compiler(
|
|||||||
val targetClass = resolveReceiverClassForMember(ref.target)
|
val targetClass = resolveReceiverClassForMember(ref.target)
|
||||||
inferFieldReturnClass(targetClass, ref.name)
|
inferFieldReturnClass(targetClass, ref.name)
|
||||||
}
|
}
|
||||||
|
is IndexRef -> {
|
||||||
|
val targetClass = resolveReceiverClassForMember(ref.targetRef)
|
||||||
|
classMethodReturnClass(targetClass, "getAt")
|
||||||
|
?: inferFieldReturnClass(targetClass, "getAt")
|
||||||
|
?: inferMethodCallReturnClass("getAt")
|
||||||
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5102,6 +5205,7 @@ class Compiler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveTypeRefClass(ref: ObjRef): ObjClass? = when (ref) {
|
private fun resolveTypeRefClass(ref: ObjRef): ObjClass? = when (ref) {
|
||||||
|
is TypeDeclRef -> resolveTypeDeclObjClass(ref.decl())
|
||||||
is ConstRef -> ref.constValue as? ObjClass
|
is ConstRef -> ref.constValue as? ObjClass
|
||||||
is LocalSlotRef -> resolveTypeDeclObjClass(TypeDecl.Simple(ref.name, false)) ?: nameObjClass[ref.name]
|
is LocalSlotRef -> resolveTypeDeclObjClass(TypeDecl.Simple(ref.name, false)) ?: nameObjClass[ref.name]
|
||||||
is LocalVarRef -> resolveTypeDeclObjClass(TypeDecl.Simple(ref.name, false)) ?: nameObjClass[ref.name]
|
is LocalVarRef -> resolveTypeDeclObjClass(TypeDecl.Simple(ref.name, false)) ?: nameObjClass[ref.name]
|
||||||
@ -7885,6 +7989,23 @@ class Compiler(
|
|||||||
val rawFnStatements = parsedFnStatements?.let { unwrapBytecodeDeep(it) }
|
val rawFnStatements = parsedFnStatements?.let { unwrapBytecodeDeep(it) }
|
||||||
val inferredReturnClass = returnTypeDecl?.let { resolveTypeDeclObjClass(it) }
|
val inferredReturnClass = returnTypeDecl?.let { resolveTypeDeclObjClass(it) }
|
||||||
?: inferReturnClassFromStatement(rawFnStatements)
|
?: inferReturnClassFromStatement(rawFnStatements)
|
||||||
|
if (declKind == SymbolKind.MEMBER && extTypeName == null) {
|
||||||
|
val ownerClassName = (parentContext as? CodeContext.ClassBody)?.name
|
||||||
|
if (ownerClassName != null) {
|
||||||
|
val returnDecl = returnTypeDecl
|
||||||
|
?: inferredReturnClass?.let { TypeDecl.Simple(it.className, false) }
|
||||||
|
if (returnDecl != null) {
|
||||||
|
classMethodReturnTypeDeclByName
|
||||||
|
.getOrPut(ownerClassName) { mutableMapOf() }[name] = returnDecl
|
||||||
|
resolveTypeDeclObjClass(returnDecl)?.let { returnClass ->
|
||||||
|
classMethodReturnTypeByName
|
||||||
|
.getOrPut(ownerClassName) { mutableMapOf() }[name] = returnClass
|
||||||
|
classFieldTypesByName
|
||||||
|
.getOrPut(ownerClassName) { mutableMapOf() }[name] = returnClass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (declKind != SymbolKind.MEMBER && inferredReturnClass != null) {
|
if (declKind != SymbolKind.MEMBER && inferredReturnClass != null) {
|
||||||
callableReturnTypeByName[name] = inferredReturnClass
|
callableReturnTypeByName[name] = inferredReturnClass
|
||||||
val slotLoc = lookupSlotLocation(name, includeModule = true)
|
val slotLoc = lookupSlotLocation(name, includeModule = true)
|
||||||
|
|||||||
@ -46,7 +46,7 @@ private val fallbackKeywordIds = setOf(
|
|||||||
"private", "protected", "static", "open", "extern", "init", "get", "set", "by", "step",
|
"private", "protected", "static", "open", "extern", "init", "get", "set", "by", "step",
|
||||||
// control flow and misc
|
// control flow and misc
|
||||||
"if", "else", "when", "while", "do", "for", "try", "catch", "finally",
|
"if", "else", "when", "while", "do", "for", "try", "catch", "finally",
|
||||||
"throw", "return", "break", "continue", "this", "null", "true", "false", "unset"
|
"throw", "return", "break", "continue", "this", "null", "true", "false", "unset", "void"
|
||||||
)
|
)
|
||||||
|
|
||||||
/** Maps lexer token type (and sometimes value) to a [HighlightKind]. */
|
/** Maps lexer token type (and sometimes value) to a [HighlightKind]. */
|
||||||
|
|||||||
@ -179,6 +179,7 @@ object LyngLanguageTools {
|
|||||||
val source = analysis.source
|
val source = analysis.source
|
||||||
val out = ArrayList<LyngSemanticSpan>(128)
|
val out = ArrayList<LyngSemanticSpan>(128)
|
||||||
val covered = HashSet<Pair<Int, Int>>()
|
val covered = HashSet<Pair<Int, Int>>()
|
||||||
|
fun isCurrentSource(pos: Pos): Boolean = pos.source === source
|
||||||
|
|
||||||
fun addRange(start: Int, end: Int, kind: LyngSemanticKind) {
|
fun addRange(start: Int, end: Int, kind: LyngSemanticKind) {
|
||||||
if (start < 0 || end <= start || end > analysis.text.length) return
|
if (start < 0 || end <= start || end > analysis.text.length) return
|
||||||
@ -187,6 +188,7 @@ object LyngLanguageTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addName(pos: Pos, name: String, kind: LyngSemanticKind) {
|
fun addName(pos: Pos, name: String, kind: LyngSemanticKind) {
|
||||||
|
if (!isCurrentSource(pos)) return
|
||||||
val s = source.offsetOf(pos)
|
val s = source.offsetOf(pos)
|
||||||
addRange(s, s + name.length, kind)
|
addRange(s, s + name.length, kind)
|
||||||
}
|
}
|
||||||
@ -206,8 +208,10 @@ object LyngLanguageTools {
|
|||||||
addTypeSegments(t.returnType)
|
addTypeSegments(t.returnType)
|
||||||
}
|
}
|
||||||
is MiniTypeVar -> {
|
is MiniTypeVar -> {
|
||||||
|
if (isCurrentSource(t.range.start) && isCurrentSource(t.range.end)) {
|
||||||
addRange(source.offsetOf(t.range.start), source.offsetOf(t.range.end), LyngSemanticKind.TypeRef)
|
addRange(source.offsetOf(t.range.start), source.offsetOf(t.range.end), LyngSemanticKind.TypeRef)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
is MiniTypeUnion -> {
|
is MiniTypeUnion -> {
|
||||||
t.options.forEach { addTypeSegments(it) }
|
t.options.forEach { addTypeSegments(it) }
|
||||||
}
|
}
|
||||||
@ -262,9 +266,11 @@ object LyngLanguageTools {
|
|||||||
|
|
||||||
mini.imports.forEach { imp ->
|
mini.imports.forEach { imp ->
|
||||||
imp.segments.forEach { seg ->
|
imp.segments.forEach { seg ->
|
||||||
|
if (isCurrentSource(seg.range.start) && isCurrentSource(seg.range.end)) {
|
||||||
addRange(source.offsetOf(seg.range.start), source.offsetOf(seg.range.end), LyngSemanticKind.TypeRef)
|
addRange(source.offsetOf(seg.range.start), source.offsetOf(seg.range.end), LyngSemanticKind.TypeRef)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun addParams(params: List<MiniParam>) {
|
fun addParams(params: List<MiniParam>) {
|
||||||
params.forEach { p -> addName(p.nameStart, p.name, LyngSemanticKind.Parameter) }
|
params.forEach { p -> addName(p.nameStart, p.name, LyngSemanticKind.Parameter) }
|
||||||
|
|||||||
@ -565,19 +565,6 @@ class TypesTest {
|
|||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test
|
|
||||||
// fun testNullableGenericTypes() = runTest {
|
|
||||||
// eval("""
|
|
||||||
// fun t<T>(): String =
|
|
||||||
// when(T) {
|
|
||||||
// is Object -> "%s is Object"(T::class.name)
|
|
||||||
// else -> throw "It should not happen"
|
|
||||||
// }
|
|
||||||
// assert( Int is Object)
|
|
||||||
// assertEquals( t<Int>(), "Class is Object")
|
|
||||||
// """.trimIndent())
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Test fun testIndexer() = runTest {
|
@Test fun testIndexer() = runTest {
|
||||||
eval("""
|
eval("""
|
||||||
class Greeter {
|
class Greeter {
|
||||||
@ -596,6 +583,38 @@ class TypesTest {
|
|||||||
|
|
||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun testIndexer2() = runTest {
|
||||||
|
eval("""
|
||||||
|
class Foo(bar)
|
||||||
|
|
||||||
|
class Greeter {
|
||||||
|
override fun getAt(name): Foo = Foo("Hello, %s!"(name))
|
||||||
|
}
|
||||||
|
assertEquals("Hello, Bob!",Greeter()["Bob"].bar)
|
||||||
|
val g = Greeter()
|
||||||
|
assertEquals("Hello, Bob!",g["Bob"].bar)
|
||||||
|
|
||||||
|
// it should work with objects too:
|
||||||
|
object Polite {
|
||||||
|
override fun getAt(name): Foo? = Foo("How do you do, %s?"(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("How do you do, Bob?",Polite["Bob"].bar)
|
||||||
|
assertEquals("How do you do, Bob?",Polite["Bob"]?.bar)
|
||||||
|
assertEquals("How do you do, Bob?",Polite["Bob"]!!.bar)
|
||||||
|
|
||||||
|
class Greeter2 {
|
||||||
|
override fun getAt(name): Foo? = Foo("How do you do, %s?"(name))
|
||||||
|
}
|
||||||
|
val g2 = Greeter2()
|
||||||
|
assertEquals("How do you do, Bob?",g2["Bob"]?.bar)
|
||||||
|
val g2v: Foo = g2["Bob"]!!
|
||||||
|
assertEquals("How do you do, Bob?",g2v.bar)
|
||||||
|
assertEquals("How do you do, Bob?",Greeter2()["Bob"].bar)
|
||||||
|
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
// @Test fun nonTrivialOperatorsTest() = runTest {
|
// @Test fun nonTrivialOperatorsTest() = runTest {
|
||||||
// val s = Script.newScope()
|
// val s = Script.newScope()
|
||||||
// s.eval("""
|
// s.eval("""
|
||||||
|
|||||||
@ -18,8 +18,9 @@
|
|||||||
package net.sergeych.lyng.tools
|
package net.sergeych.lyng.tools
|
||||||
|
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import net.sergeych.lyng.miniast.MiniClassDecl
|
import net.sergeych.lyng.Pos
|
||||||
import net.sergeych.lyng.miniast.MiniMemberTypeAliasDecl
|
import net.sergeych.lyng.Source
|
||||||
|
import net.sergeych.lyng.miniast.*
|
||||||
import net.sergeych.lyng.stdlib_included.rootLyng
|
import net.sergeych.lyng.stdlib_included.rootLyng
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -127,4 +128,48 @@ class LyngLanguageToolsTest {
|
|||||||
val dis = LyngLanguageTools.disassembleSymbol(code, "add")
|
val dis = LyngLanguageTools.disassembleSymbol(code, "add")
|
||||||
assertTrue(!dis.contains("not a compiled body"), "Disassembly should be produced, got: $dis")
|
assertTrue(!dis.contains("not a compiled body"), "Disassembly should be produced, got: $dis")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun languageTools_semanticHighlights_ignore_foreign_sources() {
|
||||||
|
val localSource = Source("local.lyng", "val x = 1")
|
||||||
|
val foreignSource = Source("defs.lyng.d", "val y = 2")
|
||||||
|
val localStart = Pos(localSource, 0, 0)
|
||||||
|
val foreignStart = Pos(foreignSource, 0, 0)
|
||||||
|
|
||||||
|
val mini = MiniScript(
|
||||||
|
range = MiniRange(localStart, localStart),
|
||||||
|
declarations = mutableListOf(
|
||||||
|
MiniValDecl(
|
||||||
|
range = MiniRange(foreignStart, foreignStart),
|
||||||
|
name = "y",
|
||||||
|
mutable = false,
|
||||||
|
type = null,
|
||||||
|
initRange = null,
|
||||||
|
doc = null,
|
||||||
|
nameStart = foreignStart
|
||||||
|
)
|
||||||
|
),
|
||||||
|
imports = mutableListOf(
|
||||||
|
MiniImport(
|
||||||
|
range = MiniRange(foreignStart, foreignStart),
|
||||||
|
segments = listOf(
|
||||||
|
MiniImport.Segment("defs", MiniRange(foreignStart, foreignStart))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val analysis = LyngAnalysisResult(
|
||||||
|
source = localSource,
|
||||||
|
text = localSource.text,
|
||||||
|
mini = mini,
|
||||||
|
binding = null,
|
||||||
|
resolution = null,
|
||||||
|
importedModules = emptyList(),
|
||||||
|
diagnostics = emptyList(),
|
||||||
|
lexicalHighlights = emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
|
val spans = LyngLanguageTools.semanticHighlights(analysis)
|
||||||
|
assertTrue(spans.isEmpty(), "Semantic spans should ignore positions from foreign sources, got $spans")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package lyng.stdlib
|
package lyng.stdlib
|
||||||
|
|
||||||
extern fun flow(builder: FlowBuilder.()->Void): Flow
|
extern fun flow(builder: FlowBuilder.()->void): Flow
|
||||||
|
|
||||||
/* Built-in exception type. */
|
/* Built-in exception type. */
|
||||||
extern class Exception
|
extern class Exception
|
||||||
@ -9,7 +9,7 @@ extern class NotImplementedException
|
|||||||
extern class Delegate
|
extern class Delegate
|
||||||
extern class Iterable<T> {
|
extern class Iterable<T> {
|
||||||
fun iterator(): Iterator<T>
|
fun iterator(): Iterator<T>
|
||||||
fun forEach(action: (T)->Void): Void
|
fun forEach(action: (T)->void): void
|
||||||
fun map<R>(transform: (T)->R): List<R>
|
fun map<R>(transform: (T)->R): List<R>
|
||||||
fun toList(): List<T>
|
fun toList(): List<T>
|
||||||
fun toImmutableList(): ImmutableList<T>
|
fun toImmutableList(): ImmutableList<T>
|
||||||
@ -22,7 +22,7 @@ extern class Iterable<T> {
|
|||||||
extern class Iterator<T> {
|
extern class Iterator<T> {
|
||||||
fun hasNext(): Bool
|
fun hasNext(): Bool
|
||||||
fun next(): T
|
fun next(): T
|
||||||
fun cancelIteration(): Void
|
fun cancelIteration(): void
|
||||||
fun toList(): List<T>
|
fun toList(): List<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,14 +44,14 @@ extern class ImmutableList<T> : Array<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern class List<T> : Array<T> {
|
extern class List<T> : Array<T> {
|
||||||
fun add(value: T, more...): Void
|
fun add(value: T, more...): void
|
||||||
fun toImmutable(): ImmutableList<T>
|
fun toImmutable(): ImmutableList<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
extern class RingBuffer<T> : Iterable<T> {
|
extern class RingBuffer<T> : Iterable<T> {
|
||||||
val size: Int
|
val size: Int
|
||||||
fun first(): T
|
fun first(): T
|
||||||
fun add(value: T): Void
|
fun add(value: T): void
|
||||||
}
|
}
|
||||||
|
|
||||||
extern class Set<T> : Collection<T> {
|
extern class Set<T> : Collection<T> {
|
||||||
@ -337,17 +337,17 @@ override fun List<T>.toString() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Sort list in-place by key selector. */
|
/* Sort list in-place by key selector. */
|
||||||
fun List<T>.sortBy<R>(predicate: (T)->R): Void {
|
fun List<T>.sortBy<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<T>.sort(): Void {
|
fun List<T>.sort(): 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(): Void {
|
fun Exception.printStackTrace(): void {
|
||||||
println(this)
|
println(this)
|
||||||
for( entry in stackTrace ) {
|
for( entry in stackTrace ) {
|
||||||
println("\tat "+entry.toString())
|
println("\tat "+entry.toString())
|
||||||
@ -357,7 +357,7 @@ fun Exception.printStackTrace(): Void {
|
|||||||
/* Compile this string into a regular expression. */
|
/* Compile this string into a regular expression. */
|
||||||
val String.re: Regex get() = Regex(this)
|
val String.re: Regex get() = Regex(this)
|
||||||
|
|
||||||
fun TODO(message: Object?=null): Void {
|
fun TODO(message: Object?=null): void {
|
||||||
throw "not implemented"
|
throw "not implemented"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,12 +376,12 @@ 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<T,ThisRefType=Void> {
|
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: ThisRefType, name: String): T = 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: ThisRefType, name: String, newValue: T): Void = 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: ThisRefType, name: String, args...): Object = TODO("delegate invoke is not implemented")
|
fun invoke(thisRef: ThisRefType, name: String, args...): Object = TODO("delegate invoke is not implemented")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user