diff --git a/chapi-ast-go/src/main/kotlin/chapi/ast/goast/GoFullIdentListener.kt b/chapi-ast-go/src/main/kotlin/chapi/ast/goast/GoFullIdentListener.kt index f6e9ddbb..aff18011 100644 --- a/chapi-ast-go/src/main/kotlin/chapi/ast/goast/GoFullIdentListener.kt +++ b/chapi-ast-go/src/main/kotlin/chapi/ast/goast/GoFullIdentListener.kt @@ -2,6 +2,7 @@ package chapi.ast.goast import chapi.ast.antlr.GoParser import chapi.domain.core.* +import chapi.infra.Stack import org.antlr.v4.runtime.tree.TerminalNodeImpl /** @@ -57,6 +58,28 @@ class GoFullIdentListener(var fileName: String) : GoAstListener() { currentFunction = CodeFunction() } + + private var blockStack = Stack() + private var lastBlock = CodeFunction(Type = FunctionType.Block, Name = "chapi_block") + + override fun enterBlock(ctx: GoParser.BlockContext?) { + if (ctx?.parent is GoParser.StatementContext) { + lastBlock = CodeFunction(Type = FunctionType.Block, Name = "chapi_block" + "${blockStack.count()}") + blockStack.push(lastBlock) + } + } + + override fun exitBlock(ctx: GoParser.BlockContext?) { + if (ctx?.parent is GoParser.StatementContext) { + val popBlock = blockStack.pop()!! + if (blockStack.count() > 0) { + blockStack.peek()!!.InnerFunctions += popBlock + } else { + currentFunction.InnerFunctions += popBlock + } + } + } + override fun enterTypeDecl(ctx: GoParser.TypeDeclContext?) { ctx?.typeSpec()?.forEach { buildTypeSpec(it) @@ -126,7 +149,7 @@ class GoFullIdentListener(var fileName: String) : GoAstListener() { } private fun buildTypeSpec(typeSpec: GoParser.TypeSpecContext) { - val identifyName = typeSpec.IDENTIFIER().text + val identifyName = typeSpec.IDENTIFIER()?.text ?: "" typeSpec.type_().typeLit()?.let { when (val typeChild = it.getChild(0)) { is GoParser.StructTypeContext -> { @@ -190,7 +213,11 @@ class GoFullIdentListener(var fileName: String) : GoAstListener() { codeCall.Parameters = parseArguments(child) codeCall.Package = wrapTarget(codeCall.NodeName) - currentFunction.FunctionCalls += codeCall + if (blockStack.count() > 0) { + lastBlock.FunctionCalls += codeCall + } else { + currentFunction.FunctionCalls += codeCall + } } else -> { diff --git a/chapi-ast-go/src/test/kotlin/chapi/ast/goast/GoAnalyserTest.kt b/chapi-ast-go/src/test/kotlin/chapi/ast/goast/GoAnalyserTest.kt index 017789ac..327885c7 100644 --- a/chapi-ast-go/src/test/kotlin/chapi/ast/goast/GoAnalyserTest.kt +++ b/chapi-ast-go/src/test/kotlin/chapi/ast/goast/GoAnalyserTest.kt @@ -99,19 +99,28 @@ func installController(g *gin.Engine) *gin.Engine { }""" val codeContainer = GoAnalyser().analysis(code, "") - val value = codeContainer.DataStructures[0] - val secondCall = value.Functions[0].FunctionCalls[1] + val container = codeContainer.DataStructures[0] + + val mainCall = container.Functions[0].FunctionCalls[1] + + assertEquals(container.Functions.size, 1) + assertEquals(mainCall.FunctionName, "Group") + assertEquals(mainCall.Parameters[0].TypeValue, "/v1") + + val firstBlock = container.Functions[0].InnerFunctions[0] + val innelCall = firstBlock.FunctionCalls[0] - assertEquals(secondCall.FunctionName, "Group") - assertEquals(secondCall.Parameters[0].TypeValue, "/v1") + assertEquals(innelCall.FunctionName, "Group") + assertEquals(innelCall.NodeName, "*gin.Engine") + assertEquals(innelCall.Parameters[0].TypeValue, "/users") - val thirdCall = value.Functions[0].FunctionCalls[2] + val secondBlock = container.Functions[0].InnerFunctions[0].InnerFunctions[0] + val innerInnerCall = secondBlock.FunctionCalls[0] - assertEquals(thirdCall.FunctionName, "Group") - assertEquals(thirdCall.NodeName, "*gin.Engine") - assertEquals(thirdCall.Parameters[0].TypeValue, "/users") + assertEquals(innerInnerCall.FunctionName, "NewUserController") - println(Json.encodeToString(value)) + val innerInnerSecondCall = secondBlock.FunctionCalls[1] + assertEquals(innerInnerSecondCall.FunctionName, "GET") } @Test diff --git a/chapi-domain/src/main/kotlin/chapi/domain/core/CodeFunction.kt b/chapi-domain/src/main/kotlin/chapi/domain/core/CodeFunction.kt index 096cfd00..a0e11326 100644 --- a/chapi-domain/src/main/kotlin/chapi/domain/core/CodeFunction.kt +++ b/chapi-domain/src/main/kotlin/chapi/domain/core/CodeFunction.kt @@ -7,6 +7,12 @@ import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonObject +enum class FunctionType { + Function, + // for Golang block + Block, +} + @Serializable open class CodeFunction( var Name: String = "", @@ -29,6 +35,7 @@ open class CodeFunction( var IsConstructor: Boolean = false, // todo: move to extension var IsReturnHtml: Boolean = false, var BodyHash: Int = 0, + var Type: FunctionType = FunctionType.Function, // a experimental api for code analysis, please carefully use it. // @property:ExperimentalStdlibApi val expression: Expression? = null, ) {