From 8f6171c6d9f411c41b525896798c32101e1afeff Mon Sep 17 00:00:00 2001 From: Disheng Su Date: Sat, 24 Jul 2021 23:30:49 -0700 Subject: [PATCH 1/8] fix ut --- src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt | 8 ++++---- src/testdata/parsing/Comments.zig | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt index 0def8fd..ba37625 100644 --- a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt +++ b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt @@ -11,7 +11,7 @@ class ZigLangCodeCompletionTest: LightPlatformCodeInsightFixture4TestCase() { myFixture.type("p") val l = myFixture.completeBasic() - assertTrue(l.size == 1) + assertTrue(l.size == 3) assertEquals(l[0].lookupString, "${ZigLangTypes.PUB} ") } @@ -41,7 +41,7 @@ class ZigLangCodeCompletionTest: LightPlatformCodeInsightFixture4TestCase() { myFixture.type("fn main() i") val l = myFixture.completeBasic() - assertTrue(l.size == 13) + assertTrue(l.size == 15) } @Test @@ -84,9 +84,9 @@ class ZigLangCodeCompletionTest: LightPlatformCodeInsightFixture4TestCase() { fun testRefMemberFieldPrimitiveType() { myFixture.configureByText(ZigFileType, "") - myFixture.type("const Point = struct {x:i3") + myFixture.type("const Bar = struct {x: i32}; const Point = struct {x:B") val l = myFixture.completeBasic() - assertTrue(l[0].lookupString == "i32") + assertTrue(l[0].lookupString == "Bar") } @Test diff --git a/src/testdata/parsing/Comments.zig b/src/testdata/parsing/Comments.zig index 4cc9b40..aeeb98f 100644 --- a/src/testdata/parsing/Comments.zig +++ b/src/testdata/parsing/Comments.zig @@ -1 +1 @@ -const Bar = struct {bar: i32}; fn a() {const b = Bar {.b \ No newline at end of file +const Point = struct {x:i3 \ No newline at end of file From 0fb68f513be409c742aa7b7329b61a0b4a64420e Mon Sep 17 00:00:00 2001 From: Disheng Su Date: Sun, 25 Jul 2021 02:07:50 -0700 Subject: [PATCH 2/8] type auto for struct --- src/main/kotlin/org/zig/psi/utils.kt | 46 ++++++++++++++++++- .../kotlin/org/zig/reference/SymbolMixin.kt | 8 ++-- .../zig/reference/ZigReferenceContributor.kt | 2 +- .../org/zig/reference/ZigTypeReference.kt | 31 +++++++++++++ .../org/zig/ZigLangCodeCompletionTest.kt | 11 ++++- src/testdata/parsing/Comments.zig | 6 ++- 6 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/org/zig/reference/ZigTypeReference.kt diff --git a/src/main/kotlin/org/zig/psi/utils.kt b/src/main/kotlin/org/zig/psi/utils.kt index 65f07d6..b50a304 100644 --- a/src/main/kotlin/org/zig/psi/utils.kt +++ b/src/main/kotlin/org/zig/psi/utils.kt @@ -1,6 +1,7 @@ package org.zig.psi import com.intellij.psi.PsiElement +import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.tree.IElementType import com.intellij.psi.util.PsiTreeUtil @@ -17,7 +18,7 @@ fun PsiElement.prevSiblingTypeIgnoring( } } -fun psiTreeWalkupInsideBlock(element: PsiElement, consumer: (ZigLocalVarDecl) -> Boolean) { +fun psiTreeWalkupInsideBlock(element: PsiElement, consumer: (PsiNameIdentifierOwner) -> Boolean) { var statement = PsiTreeUtil.findFirstParent(element) { it is ZigStatement } while (statement != null) { var e: PsiElement? = statement.prevSibling @@ -56,4 +57,47 @@ fun findPsiElementByNameInsideFile(name: String, start: PsiElement): PsiElement? return PsiTreeUtil.collectElementsOfType( start.containingFile, ZigTopVarDecl::class.java ).firstOrNull { it.nameIdentifier?.text == name } +} + +private fun isElementAType(e: PsiElement): Boolean { + return ((e is ZigTopVarDecl || e is ZigLocalVarDecl) && PsiTreeUtil.findChildOfType(e, ZigContainerDecl::class.java) != null) || e is ZigFnDecl +} + +fun findTypesInsideBlock(start: PsiElement): List { + val types = mutableListOf() + psiTreeWalkupInsideBlock(start) { + if (isElementAType(it)) { + types.add(it) + } + false + } + return types +} + +fun findTopLevelTypes(e: PsiElement): List { + val types = mutableListOf() + + PsiTreeUtil.collectElementsOfType( + e.containingFile, ZigTopVarDecl::class.java + ).forEach { + if (isElementAType(it)) { + types.add(it) + } + } + + PsiTreeUtil.collectElementsOfType( + e.containingFile, ZigFnDecl::class.java + ).forEach { + if (isElementAType(it)) { + types.add(it) + } + } + return types +} + +fun findTypesInsideFile(start: PsiElement): List { + val types = mutableListOf() + types.addAll(findTypesInsideBlock(start)) + types.addAll(findTopLevelTypes(start)) + return types } \ No newline at end of file diff --git a/src/main/kotlin/org/zig/reference/SymbolMixin.kt b/src/main/kotlin/org/zig/reference/SymbolMixin.kt index ac11463..d2dcbc6 100644 --- a/src/main/kotlin/org/zig/reference/SymbolMixin.kt +++ b/src/main/kotlin/org/zig/reference/SymbolMixin.kt @@ -4,12 +4,10 @@ import com.intellij.extapi.psi.ASTWrapperPsiElement import com.intellij.lang.ASTNode import com.intellij.psi.PsiElement import com.intellij.psi.PsiReference +import com.intellij.psi.TokenType import com.intellij.psi.util.PsiTreeUtil import org.zig.ZigReference -import org.zig.psi.ZigFieldInit -import org.zig.psi.ZigLangTypes -import org.zig.psi.ZigPrimaryTypeExpr -import org.zig.psi.ZigSuffixOp +import org.zig.psi.* import org.zig.types.Type import org.zig.types.getTypeFromChain import org.zig.types.type @@ -24,6 +22,8 @@ abstract class SymbolMixin(node: ASTNode) : ASTWrapperPsiElement(node) { } else if (ps?.text == ZigLangTypes.DOT.toString() && parent is ZigFieldInit) { val pTypeExpr: PsiElement? = PsiTreeUtil.findSiblingBackward(parent.parent, ZigLangTypes.PRIMARY_TYPE_EXPR, null) containerType = (pTypeExpr as ZigPrimaryTypeExpr).type + } else if (parent is ZigPrimaryTypeExpr && parent.prevSiblingTypeIgnoring(ZigLangTypes.COLON, TokenType.WHITE_SPACE) != null) { + return ZigTypeReference(this, node.firstChildNode?.psi!!) } return if (containerType != null) { diff --git a/src/main/kotlin/org/zig/reference/ZigReferenceContributor.kt b/src/main/kotlin/org/zig/reference/ZigReferenceContributor.kt index 96e21cf..dc015cc 100644 --- a/src/main/kotlin/org/zig/reference/ZigReferenceContributor.kt +++ b/src/main/kotlin/org/zig/reference/ZigReferenceContributor.kt @@ -68,7 +68,7 @@ class ZigReference(element: PsiElement, private val id: PsiElement) : val topVarDecl = PsiTreeUtil.collectElementsOfType( element.containingFile, ZigTopVarDecl::class.java ) - val localVars = mutableListOf() + val localVars = mutableListOf() psiTreeWalkupInsideBlock(element) { localVars.add(it) false diff --git a/src/main/kotlin/org/zig/reference/ZigTypeReference.kt b/src/main/kotlin/org/zig/reference/ZigTypeReference.kt new file mode 100644 index 0000000..8b0a023 --- /dev/null +++ b/src/main/kotlin/org/zig/reference/ZigTypeReference.kt @@ -0,0 +1,31 @@ +package org.zig.reference + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementResolveResult +import com.intellij.psi.PsiPolyVariantReferenceBase +import com.intellij.psi.ResolveResult +import org.zig.ZigLangHelper +import org.zig.psi.findTypesInsideFile + +class ZigTypeReference(element: PsiElement, private val id: PsiElement) : + PsiPolyVariantReferenceBase(element) { + override fun multiResolve(incompleteCode: Boolean): Array { + val r = mutableListOf() + val e = findTypesInsideFile(element).find { + it.nameIdentifier?.text == id.text + } + if (e != null) r.add(PsiElementResolveResult(e, true)) + return r.toTypedArray() + } + + override fun calculateDefaultRangeInElement(): TextRange { + return TextRange.from(id.startOffsetInParent, id.textLength) + } + + override fun getVariants(): Array { + return (findTypesInsideFile(element).map { + createLookup(it.nameIdentifier?.text!!) + } + ZigLangHelper.primitiveTypesLookup).toTypedArray() + } +} \ No newline at end of file diff --git a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt index ba37625..d93553c 100644 --- a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt +++ b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt @@ -81,7 +81,7 @@ class ZigLangCodeCompletionTest: LightPlatformCodeInsightFixture4TestCase() { } @Test - fun testRefMemberFieldPrimitiveType() { + fun testRefMemberFieldStruct() { myFixture.configureByText(ZigFileType, "") myFixture.type("const Bar = struct {x: i32}; const Point = struct {x:B") @@ -89,6 +89,15 @@ class ZigLangCodeCompletionTest: LightPlatformCodeInsightFixture4TestCase() { assertTrue(l[0].lookupString == "Bar") } + @Test + fun testRefMemberFieldPrimitiveType() { + myFixture.configureByText(ZigFileType, "") + + myFixture.type("const Point = struct {x: i3") + val l = myFixture.completeBasic() + assertTrue(l[0].lookupString == "i32") + } + @Test fun testStructRef() { myFixture.configureByText(ZigFileType, "") diff --git a/src/testdata/parsing/Comments.zig b/src/testdata/parsing/Comments.zig index aeeb98f..dec428c 100644 --- a/src/testdata/parsing/Comments.zig +++ b/src/testdata/parsing/Comments.zig @@ -1 +1,5 @@ -const Point = struct {x:i3 \ No newline at end of file +const Point = struct {x:i32}; +pub fn m(x: Point) Point { + const a = 1; + const b = a +} \ No newline at end of file From fdbdc468670eb4231b662c2dedf664487a608d9f Mon Sep 17 00:00:00 2001 From: Disheng Su Date: Sun, 25 Jul 2021 02:17:08 -0700 Subject: [PATCH 3/8] fnproto type auto compl --- .../kotlin/org/zig/ZigLangCompletionContributor.kt | 6 ------ src/main/kotlin/org/zig/reference/SymbolMixin.kt | 4 ++++ .../kotlin/org/zig/ZigLangCodeCompletionTest.kt | 13 +++++++++++-- src/testdata/parsing/Comments.zig | 5 +---- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/org/zig/ZigLangCompletionContributor.kt b/src/main/kotlin/org/zig/ZigLangCompletionContributor.kt index f3c315b..cfeda2c 100644 --- a/src/main/kotlin/org/zig/ZigLangCompletionContributor.kt +++ b/src/main/kotlin/org/zig/ZigLangCompletionContributor.kt @@ -128,11 +128,5 @@ class ZigLangCompletionContributor : CompletionContributor() { psiElement(ZigLangTypes.BUILTINIDENTIFIER), ZigCompletionProvider(builtInFunctions) ) - - extend( - CompletionType.BASIC, - psiElement(ZigLangTypes.ID).withAncestor(6, psiElement(ZigLangTypes.FN_PROTO)), - ZigCompletionProvider(ZigLangHelper.primitiveTypesLookup) - ) } } \ No newline at end of file diff --git a/src/main/kotlin/org/zig/reference/SymbolMixin.kt b/src/main/kotlin/org/zig/reference/SymbolMixin.kt index d2dcbc6..1481a7d 100644 --- a/src/main/kotlin/org/zig/reference/SymbolMixin.kt +++ b/src/main/kotlin/org/zig/reference/SymbolMixin.kt @@ -24,6 +24,10 @@ abstract class SymbolMixin(node: ASTNode) : ASTWrapperPsiElement(node) { containerType = (pTypeExpr as ZigPrimaryTypeExpr).type } else if (parent is ZigPrimaryTypeExpr && parent.prevSiblingTypeIgnoring(ZigLangTypes.COLON, TokenType.WHITE_SPACE) != null) { return ZigTypeReference(this, node.firstChildNode?.psi!!) + } else if (parent is ZigPrimaryTypeExpr && parent.parent is ZigFnProto) { + return ZigTypeReference(this, node.firstChildNode?.psi!!) + } else if (parent is ZigPrimaryTypeExpr && parent.parent is ZigParamType) { + return ZigTypeReference(this, node.firstChildNode?.psi!!) } return if (containerType != null) { diff --git a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt index d93553c..fab8a5c 100644 --- a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt +++ b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt @@ -38,10 +38,19 @@ class ZigLangCodeCompletionTest: LightPlatformCodeInsightFixture4TestCase() { @Test fun testFnReturnType() { myFixture.configureByText(ZigFileType, "") - myFixture.type("fn main() i") + myFixture.type("fn main() i3") val l = myFixture.completeBasic() - assertTrue(l.size == 15) + assertTrue(l[0].lookupString == "i32") + } + + @Test + fun testFnParaType() { + myFixture.configureByText(ZigFileType, "") + myFixture.type("fn main(x: i3") + + val l = myFixture.completeBasic() + assertTrue(l[0].lookupString == "i32") } @Test diff --git a/src/testdata/parsing/Comments.zig b/src/testdata/parsing/Comments.zig index dec428c..c65a10c 100644 --- a/src/testdata/parsing/Comments.zig +++ b/src/testdata/parsing/Comments.zig @@ -1,5 +1,2 @@ const Point = struct {x:i32}; -pub fn m(x: Point) Point { - const a = 1; - const b = a -} \ No newline at end of file +pub fn m(x: Point \ No newline at end of file From b5370a149e484c72e40543454dad8acaaf9416a3 Mon Sep 17 00:00:00 2001 From: Disheng Su Date: Tue, 3 Aug 2021 22:00:35 -0700 Subject: [PATCH 4/8] add recursive type --- .../kotlin/org/zig/reference/SymbolMixin.kt | 6 +- src/main/kotlin/org/zig/types/Extensions.kt | 124 ++++++++++++------ src/main/kotlin/org/zig/types/Types.kt | 12 +- src/main/kotlin/org/zig/types/Utils.kt | 2 +- .../org/zig/ZigLangCodeCompletionTest.kt | 13 ++ src/testdata/parsing/Comments.zig | 7 +- 6 files changed, 113 insertions(+), 51 deletions(-) diff --git a/src/main/kotlin/org/zig/reference/SymbolMixin.kt b/src/main/kotlin/org/zig/reference/SymbolMixin.kt index 1481a7d..8220812 100644 --- a/src/main/kotlin/org/zig/reference/SymbolMixin.kt +++ b/src/main/kotlin/org/zig/reference/SymbolMixin.kt @@ -8,9 +8,7 @@ import com.intellij.psi.TokenType import com.intellij.psi.util.PsiTreeUtil import org.zig.ZigReference import org.zig.psi.* -import org.zig.types.Type -import org.zig.types.getTypeFromChain -import org.zig.types.type +import org.zig.types.* abstract class SymbolMixin(node: ASTNode) : ASTWrapperPsiElement(node) { override fun getReference(): PsiReference? { @@ -21,7 +19,7 @@ abstract class SymbolMixin(node: ASTNode) : ASTWrapperPsiElement(node) { containerType = getTypeFromChain(pTypeExpr as ZigPrimaryTypeExpr, parent) } else if (ps?.text == ZigLangTypes.DOT.toString() && parent is ZigFieldInit) { val pTypeExpr: PsiElement? = PsiTreeUtil.findSiblingBackward(parent.parent, ZigLangTypes.PRIMARY_TYPE_EXPR, null) - containerType = (pTypeExpr as ZigPrimaryTypeExpr).type + containerType = (pTypeExpr as ZigPrimaryTypeExpr).inference() } else if (parent is ZigPrimaryTypeExpr && parent.prevSiblingTypeIgnoring(ZigLangTypes.COLON, TokenType.WHITE_SPACE) != null) { return ZigTypeReference(this, node.firstChildNode?.psi!!) } else if (parent is ZigPrimaryTypeExpr && parent.parent is ZigFnProto) { diff --git a/src/main/kotlin/org/zig/types/Extensions.kt b/src/main/kotlin/org/zig/types/Extensions.kt index 40e1973..fdffb48 100644 --- a/src/main/kotlin/org/zig/types/Extensions.kt +++ b/src/main/kotlin/org/zig/types/Extensions.kt @@ -5,63 +5,109 @@ import com.intellij.psi.util.PsiTreeUtil import org.zig.ZigLangHelper.primitiveTypes import org.zig.psi.* -private fun getStructType(e: ZigContainerDecl): StructType { - val fieldNameToTypeMap = - PsiTreeUtil - .findChildrenOfType(e, ZigContainerField::class.java) - .associate { - it.firstChild?.text!! to FieldType(it, PsiTreeUtil.findChildOfType(it, ZigPrimaryTypeExpr::class.java)?.type) - } - return StructType(e, fieldNameToTypeMap) +data class UnknownType(val e: PsiElement, val t: Type, val handler: (Type) -> Unit) +class Context(private val visitedTypes: MutableMap, val unknownTypes: MutableSet) { + fun cacheType(e: PsiElement, getType: () -> Type?): Type? { + val cachedType = visitedTypes[e] + if (cachedType != null) return cachedType + + val t = getType() ?: return null + visitedTypes[e] = t + return t + } } -val ZigContainerDecl.type: Type? - get() { - return when (firstChild?.firstChild?.text) { - ZigLangTypes.STRUCT.toString().toLowerCase() -> getStructType(this) - else -> null +private fun getStructType(ctx: Context, e: ZigContainerDecl): StructType { + val fieldTypeMap = mutableMapOf() + e.children.forEach { + when (it) { + is ZigContainerField -> + fieldTypeMap[it.firstChild?.text!!] = + FieldType(it, PsiTreeUtil.getChildOfType(it, ZigPrimaryTypeExpr::class.java)?.type(ctx)) + is ZigFnDecl -> + fieldTypeMap[it.nameIdentifier?.text!!] = FieldType(it, it.type(ctx)) + is ZigTopVarDecl -> + fieldTypeMap[it.nameIdentifier?.text!!] = FieldType(it, it.type(ctx)) } } -val ZigSymbol.type: Type? - get() { - val id = firstChild?.text ?: return null - return if (id in primitiveTypes) { - BuildinType(id) - } else { - val e = findPsiElementByNameInsideFile(id, this) - e?.type + return StructType(e, fieldTypeMap) +} + +fun ZigFnDecl.type(ctx: Context): Type? { + return ctx.cacheType(this) { + + val t = FnType(this, null) + val ut = UnknownType(this, t) { + val fnType = it as FnType + + val fnProto = PsiTreeUtil.getChildOfType(this, ZigFnProto::class.java) ?: return@UnknownType + val returnType = PsiTreeUtil.getChildOfType(fnProto, ZigPrimaryTypeExpr::class.java)?.type(ctx) + fnType.returnType = returnType } + ctx.unknownTypes.add(ut) + t } +} -val ZigPrimaryTypeExpr.type: Type? - get() { - return when (val c = firstChild) { - is ZigContainerDecl -> c.type - is ZigSymbol -> c.type +fun ZigContainerDecl.type(ctx: Context): Type? { + return ctx.cacheType(this) { + when (firstChild?.firstChild?.text) { + ZigLangTypes.STRUCT.toString().toLowerCase() -> getStructType(ctx, this) else -> null } } +} -val ZigTopVarDecl.type: Type? - get() { - return PsiTreeUtil.findChildOfType(this, ZigPrimaryTypeExpr::class.java)?.type +fun ZigSymbol.type(ctx: Context): Type? { + val id = firstChild?.text ?: return null + return ctx.cacheType(this) { + if (id in primitiveTypes) { + BuildinType(id) + } else { + val e = findPsiElementByNameInsideFile(id, this) + e?.type(ctx) + } } +} -val ZigLocalVarDecl.type: Type? - get() { - return PsiTreeUtil.findChildOfType(this, ZigPrimaryTypeExpr::class.java)?.type +fun ZigPrimaryTypeExpr.type(ctx: Context): Type? { + return when (val c = firstChild) { + is ZigContainerDecl -> c.type(ctx) + is ZigSymbol -> c.type(ctx) + else -> null } +} -val PsiElement.type: Type? - get() { - return when (this) { - is ZigTopVarDecl -> type - is ZigLocalVarDecl -> type - else -> null - } +fun ZigTopVarDecl.type(ctx: Context): Type? { + return PsiTreeUtil.findChildOfType(this, ZigPrimaryTypeExpr::class.java)?.type(ctx) +} + +fun ZigLocalVarDecl.type(ctx: Context): Type? { + return PsiTreeUtil.findChildOfType(this, ZigPrimaryTypeExpr::class.java)?.type(ctx) +} + +fun PsiElement.type(ctx: Context): Type? { + return when (this) { + is ZigTopVarDecl -> type(ctx) + is ZigLocalVarDecl -> type(ctx) + is ZigPrimaryTypeExpr -> type(ctx) + is ZigSymbol -> type(ctx) + is ZigFnDecl -> type(ctx) + else -> null } +} +fun PsiElement.inference(): Type? { + val ctx = Context(mutableMapOf(), mutableSetOf()) + val t = this.type(ctx) + while(ctx.unknownTypes.isNotEmpty()) { + val ut = ctx.unknownTypes.first() + ut.handler(ut.t) + ctx.unknownTypes.remove(ut) + } + return t +} val PsiElement.leftSiblings: Sequence get() = generateSequence(this.prevSibling) { it.prevSibling } diff --git a/src/main/kotlin/org/zig/types/Types.kt b/src/main/kotlin/org/zig/types/Types.kt index 6fa5d4d..0f8135e 100644 --- a/src/main/kotlin/org/zig/types/Types.kt +++ b/src/main/kotlin/org/zig/types/Types.kt @@ -2,7 +2,8 @@ package org.zig.types import com.intellij.psi.PsiElement -open class Type(private val owner: PsiElement?) { + +open class Type(val owner: PsiElement?) { fun reference(): PsiElement? { return owner } @@ -10,9 +11,10 @@ open class Type(private val owner: PsiElement?) { class FieldType(ref: PsiElement, val type: Type?) : Type(ref) -class StructType(owner: PsiElement, val fields: Map) : Type(owner) { -} +class StructType(owner: PsiElement, val fields: Map) : Type(owner) + +class FnType(owner: PsiElement, var returnType: Type?) : Type(owner) -class BuildinType(name: String) : Type(null) {} +class BuildinType(name: String) : Type(null) -class EnumType(owner: PsiElement?) : Type(owner) {} +class EnumType(owner: PsiElement?) : Type(owner) diff --git a/src/main/kotlin/org/zig/types/Utils.kt b/src/main/kotlin/org/zig/types/Utils.kt index 6cff6e0..ce8d17f 100644 --- a/src/main/kotlin/org/zig/types/Utils.kt +++ b/src/main/kotlin/org/zig/types/Utils.kt @@ -5,7 +5,7 @@ import org.zig.psi.ZigPrimaryTypeExpr import org.zig.psi.ZigSuffixOp fun getTypeFromChain(start: ZigPrimaryTypeExpr, end: PsiElement): Type? { - var t = start.type + var t = start.inference() var s = start.nextSibling while (s != end) { when (s) { diff --git a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt index fab8a5c..a25b4a7 100644 --- a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt +++ b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt @@ -1,6 +1,7 @@ package org.zig import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixture4TestCase +import junit.framework.TestCase import org.junit.Test import org.zig.psi.ZigLangTypes @@ -98,6 +99,18 @@ class ZigLangCodeCompletionTest: LightPlatformCodeInsightFixture4TestCase() { assertTrue(l[0].lookupString == "Bar") } + @Test + fun testNestedStruct() { + myFixture.configureByText(ZigFileType, "") + + myFixture.type("const Bar = struct {x: i32, const Nested = struct {y: i32}; fn foo(x: i32) Bar;}; const a = Bar.") + val l = myFixture.completeBasic() + TestCase.assertTrue(l.size == 3) + assertTrue(l.find{it.lookupString == "x"} != null) + assertTrue(l.find{it.lookupString == "Nested"} != null) + assertTrue(l.find{it.lookupString == "foo"} != null) + } + @Test fun testRefMemberFieldPrimitiveType() { myFixture.configureByText(ZigFileType, "") diff --git a/src/testdata/parsing/Comments.zig b/src/testdata/parsing/Comments.zig index c65a10c..249e2f9 100644 --- a/src/testdata/parsing/Comments.zig +++ b/src/testdata/parsing/Comments.zig @@ -1,2 +1,5 @@ -const Point = struct {x:i32}; -pub fn m(x: Point \ No newline at end of file +const Point = struct { +x:i32, +pub fn init(x: i32) Point {} +const Bar = struct {x: i32}; +}; From 29f38c995570b778901786b1745065d5f603305c Mon Sep 17 00:00:00 2001 From: Disheng Su Date: Thu, 5 Aug 2021 01:25:05 -0700 Subject: [PATCH 5/8] support enum --- src/main/kotlin/org/zig/types/Extensions.kt | 18 ++++++++++++++++++ src/main/kotlin/org/zig/types/Types.kt | 2 -- .../org/zig/ZigLangCodeCompletionTest.kt | 13 +++++++++++++ src/testdata/parsing/Comments.zig | 3 +++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/org/zig/types/Extensions.kt b/src/main/kotlin/org/zig/types/Extensions.kt index fdffb48..7c05035 100644 --- a/src/main/kotlin/org/zig/types/Extensions.kt +++ b/src/main/kotlin/org/zig/types/Extensions.kt @@ -34,6 +34,23 @@ private fun getStructType(ctx: Context, e: ZigContainerDecl): StructType { return StructType(e, fieldTypeMap) } +private fun getEnumType(ctx: Context, e: ZigContainerDecl): StructType { + val fieldTypeMap = mutableMapOf() + e.children.forEach { + when (it) { + is ZigContainerField -> + fieldTypeMap[it.firstChild?.text!!] = + FieldType(it, BuildinType("u2")) + is ZigFnDecl -> + fieldTypeMap[it.nameIdentifier?.text!!] = FieldType(it, it.type(ctx)) + is ZigTopVarDecl -> + fieldTypeMap[it.nameIdentifier?.text!!] = FieldType(it, it.type(ctx)) + } + } + + return StructType(e, fieldTypeMap) +} + fun ZigFnDecl.type(ctx: Context): Type? { return ctx.cacheType(this) { @@ -54,6 +71,7 @@ fun ZigContainerDecl.type(ctx: Context): Type? { return ctx.cacheType(this) { when (firstChild?.firstChild?.text) { ZigLangTypes.STRUCT.toString().toLowerCase() -> getStructType(ctx, this) + ZigLangTypes.ENUM.toString().toLowerCase() -> getEnumType(ctx, this) else -> null } } diff --git a/src/main/kotlin/org/zig/types/Types.kt b/src/main/kotlin/org/zig/types/Types.kt index 0f8135e..bf920a3 100644 --- a/src/main/kotlin/org/zig/types/Types.kt +++ b/src/main/kotlin/org/zig/types/Types.kt @@ -16,5 +16,3 @@ class StructType(owner: PsiElement, val fields: Map) : Type( class FnType(owner: PsiElement, var returnType: Type?) : Type(owner) class BuildinType(name: String) : Type(null) - -class EnumType(owner: PsiElement?) : Type(owner) diff --git a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt index a25b4a7..e47ecbd 100644 --- a/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt +++ b/src/test/kotlin/org/zig/ZigLangCodeCompletionTest.kt @@ -111,6 +111,19 @@ class ZigLangCodeCompletionTest: LightPlatformCodeInsightFixture4TestCase() { assertTrue(l.find{it.lookupString == "foo"} != null) } + @Test + fun testEnum() { + myFixture.configureByText(ZigFileType, "") + + myFixture.type("const E = enum {one, two, pub fn foo() bool {}}; const e = E.") + val l = myFixture.completeBasic() + TestCase.assertTrue(l.size == 3) + assertTrue(l.find{it.lookupString == "one"} != null) + assertTrue(l.find{it.lookupString == "two"} != null) + assertTrue(l.find{it.lookupString == "foo"} != null) + + } + @Test fun testRefMemberFieldPrimitiveType() { myFixture.configureByText(ZigFileType, "") diff --git a/src/testdata/parsing/Comments.zig b/src/testdata/parsing/Comments.zig index 249e2f9..5b564d3 100644 --- a/src/testdata/parsing/Comments.zig +++ b/src/testdata/parsing/Comments.zig @@ -3,3 +3,6 @@ x:i32, pub fn init(x: i32) Point {} const Bar = struct {x: i32}; }; + +const E = enum {one, two}; +const e = E. \ No newline at end of file From 5f30cd28808a96cc4af59c2b9635718ee0e8e88e Mon Sep 17 00:00:00 2001 From: Disheng Su Date: Thu, 5 Aug 2021 01:26:41 -0700 Subject: [PATCH 6/8] add change log --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00dcd9a..a45aaf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ # IntelliJ ZigLang Plugin Changelog +## [0.3.1] +### Added +- function and type inside struct +- enum + ## [0.3.0] ### Added - Struct auto completion From 20526b8400ca93b1c1bcdc1ff269d796c99984c9 Mon Sep 17 00:00:00 2001 From: Disheng Su Date: Thu, 5 Aug 2021 01:27:20 -0700 Subject: [PATCH 7/8] bump version to 0.3.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1f6dce7..952c418 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ pluginGroup = org.zig pluginName = IntelliJ ZigLang Plugin -pluginVersion = 0.3.0 +pluginVersion = 0.3.1 # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # for insight into build numbers and IntelliJ Platform versions. From 3ec2ce28305c6b8613e3b4ae8df2288ff7b74766 Mon Sep 17 00:00:00 2001 From: Disheng Su Date: Thu, 5 Aug 2021 02:47:21 -0700 Subject: [PATCH 8/8] support import local file --- src/main/kotlin/org/zig/types/Extensions.kt | 19 +++++++++++++++---- src/testdata/parsing/Comments.zig | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/org/zig/types/Extensions.kt b/src/main/kotlin/org/zig/types/Extensions.kt index 7c05035..c2ccb18 100644 --- a/src/main/kotlin/org/zig/types/Extensions.kt +++ b/src/main/kotlin/org/zig/types/Extensions.kt @@ -1,6 +1,8 @@ package org.zig.types import com.intellij.psi.PsiElement +import com.intellij.psi.search.FilenameIndex +import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.PsiTreeUtil import org.zig.ZigLangHelper.primitiveTypes import org.zig.psi.* @@ -17,7 +19,7 @@ class Context(private val visitedTypes: MutableMap, val unkno } } -private fun getStructType(ctx: Context, e: ZigContainerDecl): StructType { +private fun getStructType(ctx: Context, e: PsiElement): StructType { val fieldTypeMap = mutableMapOf() e.children.forEach { when (it) { @@ -89,10 +91,19 @@ fun ZigSymbol.type(ctx: Context): Type? { } } +private fun getTypeFromImport(ctx: Context, e: PsiElement): StructType? { + val si = PsiTreeUtil.findChildOfType(e, ZigStringliteral::class.java) + val path = si?.firstChild?.text?.removeSurrounding("\"") ?: return null + val psiFile = FilenameIndex.getFilesByName(e.project, "$path.zig", GlobalSearchScope.projectScope(e.project)).first() ?: return null + return getStructType(ctx, psiFile) +} + fun ZigPrimaryTypeExpr.type(ctx: Context): Type? { - return when (val c = firstChild) { - is ZigContainerDecl -> c.type(ctx) - is ZigSymbol -> c.type(ctx) + val c = firstChild + return when { + c is ZigContainerDecl -> c.type(ctx) + c is ZigSymbol -> c.type(ctx) + c.text?.toString() == "@import" -> getTypeFromImport(ctx, this) else -> null } } diff --git a/src/testdata/parsing/Comments.zig b/src/testdata/parsing/Comments.zig index 5b564d3..8d5b60c 100644 --- a/src/testdata/parsing/Comments.zig +++ b/src/testdata/parsing/Comments.zig @@ -1,3 +1,4 @@ +const i = @import("a"); const Point = struct { x:i32, pub fn init(x: i32) Point {}