Skip to content

Commit

Permalink
feature: 🍺 Support for BlockStmt statement (#181)
Browse files Browse the repository at this point in the history
* 🍺 supported BlockStmt  statement

* 🍺 Fixed testcase

* 🍺 Fixed testcase

* 🍺 Fixed testcase
  • Loading branch information
shivasurya authored Nov 9, 2024
1 parent 6d7aed0 commit fa305a8
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 9 deletions.
16 changes: 16 additions & 0 deletions sourcecode-parser/graph/construct.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type Node struct {
YieldStmt *model.YieldStmt
AssertStmt *model.AssertStmt
ReturnStmt *model.ReturnStmt
BlockStmt *model.BlockStmt
}

type Edge struct {
Expand Down Expand Up @@ -183,6 +184,21 @@ func parseJavadocTags(commentContent string) *model.Javadoc {
func buildGraphFromAST(node *sitter.Node, sourceCode []byte, graph *CodeGraph, currentContext *Node, file string) {
isJavaSourceFile := isJavaSourceFile(file)
switch node.Type() {
case "block":
blockNode := javalang.ParseBlockStatement(node, sourceCode)
uniqueBlockID := fmt.Sprintf("block_%d_%d_%s", node.StartPoint().Row+1, node.StartPoint().Column+1, file)
blockStmtNode := &Node{
ID: GenerateSha256(uniqueBlockID),
Type: "BlockStmt",
LineNumber: node.StartPoint().Row + 1,
Name: "BlockStmt",
IsExternal: true,
CodeSnippet: node.Content(sourceCode),
File: file,
isJavaSourceFile: isJavaSourceFile,
BlockStmt: blockNode,
}
graph.AddNode(blockStmtNode)
case "return_statement":
returnNode := javalang.ParseReturnStatement(node, sourceCode)
uniqueReturnID := fmt.Sprintf("return_%d_%d_%s", node.StartPoint().Row+1, node.StartPoint().Column+1, file)
Expand Down
18 changes: 9 additions & 9 deletions sourcecode-parser/graph/construct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -701,9 +701,9 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 3,
expectedNodes: 4,
expectedEdges: 0,
expectedTypes: []string{"class_declaration", "method_declaration", "variable_declaration"},
expectedTypes: []string{"class_declaration", "method_declaration", "variable_declaration", "BlockStmt"},
unexpectedTypes: []string{"method_invocation"},
},
{
Expand All @@ -718,9 +718,9 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 5,
expectedNodes: 7,
expectedEdges: 2,
expectedTypes: []string{"class_declaration", "method_declaration", "method_invocation"},
expectedTypes: []string{"class_declaration", "method_declaration", "method_invocation", "BlockStmt"},
unexpectedTypes: []string{"variable_declaration"},
},
{
Expand All @@ -732,7 +732,7 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 5,
expectedNodes: 6,
expectedEdges: 0,
expectedTypes: []string{"class_declaration", "method_declaration", "binary_expression", "ReturnStmt"},
unexpectedTypes: []string{"variable_declaration"},
Expand Down Expand Up @@ -791,9 +791,9 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 74,
expectedNodes: 83,
expectedEdges: 5,
expectedTypes: []string{"class_declaration", "method_declaration", "binary_expression", "comp_expression", "and_expression", "or_expression", "IfStmt", "ForStmt", "WhileStmt", "DoStmt", "BreakStmt", "ContinueStmt", "YieldStmt", "ReturnStmt"},
expectedTypes: []string{"class_declaration", "method_declaration", "binary_expression", "comp_expression", "and_expression", "or_expression", "IfStmt", "ForStmt", "WhileStmt", "DoStmt", "BreakStmt", "ContinueStmt", "YieldStmt", "ReturnStmt", "BlockStmt"},
unexpectedTypes: []string{""},
},
{
Expand All @@ -811,7 +811,7 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 4,
expectedNodes: 5,
expectedEdges: 0,
expectedTypes: []string{"class_declaration", "method_declaration", "block_comment", "ReturnStmt"},
unexpectedTypes: []string{"variable_declaration", "binary_expression"},
Expand All @@ -827,7 +827,7 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 6,
expectedNodes: 7,
expectedEdges: 0,
expectedTypes: []string{"class_declaration", "method_declaration", "ClassInstanceExpr"},
unexpectedTypes: []string{"binary_expression"},
Expand Down
10 changes: 10 additions & 0 deletions sourcecode-parser/graph/java/parse_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,13 @@ func ParseReturnStatement(node *sitter.Node, sourcecode []byte) *model.ReturnStm
}
return returnStmt
}

func ParseBlockStatement(node *sitter.Node, sourcecode []byte) *model.BlockStmt {
blockStmt := &model.BlockStmt{}
for i := 0; i < int(node.ChildCount()); i++ {
singleBlockStmt := &model.Stmt{}
singleBlockStmt.NodeString = node.Child(i).Content(sourcecode)
blockStmt.Stmts = append(blockStmt.Stmts, *singleBlockStmt)
}
return blockStmt
}
80 changes: 80 additions & 0 deletions sourcecode-parser/graph/java/parse_statement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,83 @@ func TestParseAssertStatement(t *testing.T) {
})
}
}

func TestParseBlockStatement(t *testing.T) {
tests := []struct {
name string
input string
expected *model.BlockStmt
}{
{
name: "Empty block statement",
input: "{}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "}"},
},
},
},
{
name: "Single statement block",
input: "{return true;}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "return true;"},
{NodeString: "}"},
},
},
},
{
name: "Multiple statement block",
input: "{int x = 1; x++; return x;}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "int x = 1;"},
{NodeString: "x++;"},
{NodeString: "return x;"},
{NodeString: "}"},
},
},
},
{
name: "Nested block statements",
input: "{{int x = 1;}{int y = 2;}}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "{int x = 1;}"},
{NodeString: "{int y = 2;}"},
{NodeString: "}"},
},
},
},
{
name: "Block with complex statements",
input: "{System.out.println(\"Hello\"); if(x > 0) { return true; } throw new Exception();}",
expected: &model.BlockStmt{
Stmts: []model.Stmt{
{NodeString: "{"},
{NodeString: "System.out.println(\"Hello\");"},
{NodeString: "if(x > 0) { return true; }"},
{NodeString: "throw new Exception();"},
{NodeString: "}"},
},
},
},
}

parser := sitter.NewParser()
parser.SetLanguage(java.GetLanguage())

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tree := parser.Parse(nil, []byte(tt.input))
node := tree.RootNode().Child(0)
result := ParseBlockStatement(node, []byte(tt.input))
assert.Equal(t, tt.expected, result)
})
}
}
11 changes: 11 additions & 0 deletions sourcecode-parser/graph/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ func (env *Env) GetReturnStmt() *model.ReturnStmt {
return env.Node.ReturnStmt
}

func (env *Env) GetBlockStmt() *model.BlockStmt {
return env.Node.BlockStmt
}

func QueryEntities(graph *CodeGraph, query parser.Query) (nodes [][]*Node, output [][]interface{}) {
result := make([][]*Node, 0)

Expand Down Expand Up @@ -335,6 +339,7 @@ func generateProxyEnv(node *Node, query parser.Query) map[string]interface{} {
yieldStmt := "YieldStmt"
assertStmt := "AssertStmt"
returnStmt := "ReturnStmt"
blockStmt := "BlockStmt"

// print query select list
for _, entity := range query.SelectList {
Expand Down Expand Up @@ -401,6 +406,8 @@ func generateProxyEnv(node *Node, query parser.Query) map[string]interface{} {
assertStmt = entity.Alias
case "ReturnStmt":
returnStmt = entity.Alias
case "BlockStmt":
blockStmt = entity.Alias
}
}
env := map[string]interface{}{
Expand Down Expand Up @@ -567,6 +574,10 @@ func generateProxyEnv(node *Node, query parser.Query) map[string]interface{} {
"toString": proxyenv.ToString,
"getReturnStmt": proxyenv.GetReturnStmt,
},
blockStmt: map[string]interface{}{
"toString": proxyenv.ToString,
"getBlockStmt": proxyenv.GetBlockStmt,
},
}
return env
}
Expand Down
49 changes: 49 additions & 0 deletions sourcecode-parser/model/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,52 @@ func (returnStmt *ReturnStmt) ToString() string {
func (returnStmt *ReturnStmt) GetResult() *Expr {
return returnStmt.Result
}

type BlockStmt struct {
Stmt
Stmts []Stmt
}

type IBlockStmt interface {
GetAPrimaryQlClass() string
GetHalsteadID() int
GetPP() string
ToString() string
GetStmt(index int) Stmt
GetAStmt() Stmt
GetNumStmt() int
GetLastStmt() Stmt
}

func (blockStmt *BlockStmt) GetAPrimaryQlClass() string {
return "BlockStmt"
}

func (blockStmt *BlockStmt) GetHalsteadID() int {
// TODO: Implement Halstead ID calculation for BlockStmt
return 0
}

func (blockStmt *BlockStmt) GetPP() string {
return fmt.Sprintf("block %s", blockStmt.Stmts)
}

func (blockStmt *BlockStmt) ToString() string {
return fmt.Sprintf("block %s", blockStmt.Stmts)
}

func (blockStmt *BlockStmt) GetStmt(index int) Stmt {
return blockStmt.Stmts[index]
}

func (blockStmt *BlockStmt) GetAStmt() Stmt {
return blockStmt.Stmts[0]
}

func (blockStmt *BlockStmt) GetNumStmt() int {
return len(blockStmt.Stmts)
}

func (blockStmt *BlockStmt) GetLastStmt() Stmt {
return blockStmt.Stmts[len(blockStmt.Stmts)-1]
}
58 changes: 58 additions & 0 deletions sourcecode-parser/model/stmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,61 @@ func TestReturnStmt_GetPP(t *testing.T) {
assert.Equal(t, "return x > 0 && y < 10", returnStmt.GetPP())
})
}

func TestBlockStmt(t *testing.T) {
t.Run("GetAPrimaryQlClass", func(t *testing.T) {
blockStmt := &BlockStmt{}
assert.Equal(t, "BlockStmt", blockStmt.GetAPrimaryQlClass())
})

t.Run("GetHalsteadID", func(t *testing.T) {
blockStmt := &BlockStmt{}
assert.Equal(t, 0, blockStmt.GetHalsteadID())
})

t.Run("GetStmt with valid index", func(t *testing.T) {
stmt1 := Stmt{NodeString: "x = 1"}
stmt2 := Stmt{NodeString: "y = 2"}
blockStmt := &BlockStmt{
Stmts: []Stmt{stmt1, stmt2},
}
assert.Equal(t, stmt2, blockStmt.GetStmt(1))
})

t.Run("GetAStmt with non-empty block", func(t *testing.T) {
stmt1 := Stmt{NodeString: "x = 1"}
stmt2 := Stmt{NodeString: "y = 2"}
blockStmt := &BlockStmt{
Stmts: []Stmt{stmt1, stmt2},
}
assert.Equal(t, stmt1, blockStmt.GetAStmt())
})

t.Run("GetNumStmt with multiple statements", func(t *testing.T) {
blockStmt := &BlockStmt{
Stmts: []Stmt{
{NodeString: "x = 1"},
{NodeString: "y = 2"},
{NodeString: "z = 3"},
},
}
assert.Equal(t, 3, blockStmt.GetNumStmt())
})

t.Run("GetNumStmt with empty block", func(t *testing.T) {
blockStmt := &BlockStmt{
Stmts: []Stmt{},
}
assert.Equal(t, 0, blockStmt.GetNumStmt())
})

t.Run("GetLastStmt with multiple statements", func(t *testing.T) {
stmt1 := Stmt{NodeString: "x = 1"}
stmt2 := Stmt{NodeString: "y = 2"}
stmt3 := Stmt{NodeString: "z = 3"}
blockStmt := &BlockStmt{
Stmts: []Stmt{stmt1, stmt2, stmt3},
}
assert.Equal(t, stmt3, blockStmt.GetLastStmt())
})
}

0 comments on commit fa305a8

Please sign in to comment.