Skip to content

Commit

Permalink
🐳 added ContinueStmt support (#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
shivasurya authored Nov 4, 2024
1 parent d8bbf0c commit 67efb23
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 4 deletions.
18 changes: 17 additions & 1 deletion sourcecode-parser/graph/construct.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ type Node struct {
DoStmt *model.DoStmt
ForStmt *model.ForStmt
BreakStmt *model.BreakStmt
}
ContinueStmt *model.ContinueStmt
} //

type Edge struct {
From *Node
Expand Down Expand Up @@ -194,6 +195,21 @@ func buildGraphFromAST(node *sitter.Node, sourceCode []byte, graph *CodeGraph, c
BreakStmt: breakNode,
}
graph.AddNode(breakStmtNode)
case "continue_statement":
continueNode := javalang.ParseContinueStatement(node, sourceCode)
uniquecontinueID := fmt.Sprintf("continuestmt_%d_%d_%s", node.StartPoint().Row+1, node.StartPoint().Column+1, file)
continueStmtNode := &Node{
ID: GenerateSha256(uniquecontinueID),
Type: "ContinueStmt",
LineNumber: node.StartPoint().Row + 1,
Name: "ContinueStmt",
IsExternal: true,
CodeSnippet: node.Content(sourceCode),
File: file,
isJavaSourceFile: isJavaSourceFile,
ContinueStmt: continueNode,
}
graph.AddNode(continueStmtNode)
case "if_statement":
ifNode := model.IfStmt{}
// get the condition of the if statement
Expand Down
6 changes: 4 additions & 2 deletions sourcecode-parser/graph/construct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,8 @@ func TestBuildGraphFromAST(t *testing.T) {
a--;
if (a == 0) {
break outerlabel;
} else {
continue outerlabel;
}
}
for (int i = 0; i < 10; i++) {
Expand All @@ -776,9 +778,9 @@ func TestBuildGraphFromAST(t *testing.T) {
}
}
`,
expectedNodes: 68,
expectedNodes: 69,
expectedEdges: 4,
expectedTypes: []string{"class_declaration", "method_declaration", "binary_expression", "comp_expression", "and_expression", "or_expression", "IfStmt", "ForStmt", "WhileStmt", "DoStmt", "BreakStmt"},
expectedTypes: []string{"class_declaration", "method_declaration", "binary_expression", "comp_expression", "and_expression", "or_expression", "IfStmt", "ForStmt", "WhileStmt", "DoStmt", "BreakStmt", "ContinueStmt"},
unexpectedTypes: []string{""},
},
{
Expand Down
11 changes: 11 additions & 0 deletions sourcecode-parser/graph/java/parse_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,14 @@ func ParseBreakStatement(node *sitter.Node, sourcecode []byte) *model.BreakStmt
}
return breakStmt
}

func ParseContinueStatement(node *sitter.Node, sourcecode []byte) *model.ContinueStmt {
continueStmt := &model.ContinueStmt{}
// get identifier if present child
for i := 0; i < int(node.ChildCount()); i++ {
if node.Child(i).Type() == "identifier" {
continueStmt.Label = node.Child(i).Content(sourcecode)
}
}
return continueStmt
}
41 changes: 41 additions & 0 deletions sourcecode-parser/graph/java/parse_statement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,44 @@ func TestParseBreakStatement(t *testing.T) {
})
}
}

func TestParseContinueStatement(t *testing.T) {
tests := []struct {
name string
input string
expected *model.ContinueStmt
}{
{
name: "Simple continue statement without label",
input: "continue;",
expected: &model.ContinueStmt{Label: ""},
},
{
name: "Continue statement with label",
input: "continue outerLoop;",
expected: &model.ContinueStmt{Label: "outerLoop"},
},
{
name: "Continue statement with complex label",
input: "continue COMPLEX_LABEL_123;",
expected: &model.ContinueStmt{Label: "COMPLEX_LABEL_123"},
},
{
name: "Continue statement with underscore label",
input: "continue outer_loop_label;",
expected: &model.ContinueStmt{Label: "outer_loop_label"},
},
}

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 := ParseContinueStatement(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 @@ -139,6 +139,10 @@ func (env *Env) GetBreakStmt() *model.BreakStmt {
return env.Node.BreakStmt
}

func (env *Env) GetContinueStmt() *model.ContinueStmt {
return env.Node.ContinueStmt
}

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

Expand Down Expand Up @@ -315,6 +319,7 @@ func generateProxyEnv(node *Node, query parser.Query) map[string]interface{} {
doStmt := "DoStmt"
forStmt := "ForStmt"
breakStmt := "BreakStmt"
continueStmt := "ContinueStmt"

// print query select list
for _, entity := range query.SelectList {
Expand Down Expand Up @@ -373,6 +378,8 @@ func generateProxyEnv(node *Node, query parser.Query) map[string]interface{} {
forStmt = entity.Alias
case "BreakStmt":
breakStmt = entity.Alias
case "ContinueStmt":
continueStmt = entity.Alias
}
}
env := map[string]interface{}{
Expand Down Expand Up @@ -523,6 +530,10 @@ func generateProxyEnv(node *Node, query parser.Query) map[string]interface{} {
"toString": proxyenv.ToString,
"getBreakStmt": proxyenv.GetBreakStmt,
},
continueStmt: map[string]interface{}{
"toString": proxyenv.ToString,
"getContinueStmt": proxyenv.GetContinueStmt,
},
}
return env
}
Expand Down
39 changes: 39 additions & 0 deletions sourcecode-parser/model/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,42 @@ func (breakStmt *BreakStmt) hasLabel() bool {
func (breakStmt *BreakStmt) GetLabel() string {
return breakStmt.Label
}

type IContinueStmt interface {
GetAPrimaryQlClass() string
GetHalsteadID() int
GetLabel() string
hasLabel() bool
GetPP() string
ToString() string
}

type ContinueStmt struct {
JumpStmt
Label string
}

func (continueStmt *ContinueStmt) GetAPrimaryQlClass() string {
return "ContinueStmt"
}

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

func (continueStmt *ContinueStmt) GetPP() string {
return fmt.Sprintf("continue (%s)", continueStmt.Label)
}

func (continueStmt *ContinueStmt) ToString() string {
return fmt.Sprintf("continue (%s)", continueStmt.Label)
}

func (continueStmt *ContinueStmt) hasLabel() bool {
return continueStmt.Label != ""
}

func (continueStmt *ContinueStmt) GetLabel() string {
return continueStmt.Label
}
72 changes: 72 additions & 0 deletions sourcecode-parser/model/stmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,75 @@ func TestIfStmt(t *testing.T) {
assert.Equal(t, expected, ifStmt.ToString())
})
}

func TestContinueStmt(t *testing.T) {
t.Run("GetAPrimaryQlClass", func(t *testing.T) {
continueStmt := &ContinueStmt{}
assert.Equal(t, "ContinueStmt", continueStmt.GetAPrimaryQlClass())
})

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

t.Run("GetPP with label", func(t *testing.T) {
continueStmt := &ContinueStmt{
Label: "outerLoop",
}
expected := "continue (outerLoop)"
assert.Equal(t, expected, continueStmt.GetPP())
})

t.Run("GetPP without label", func(t *testing.T) {
continueStmt := &ContinueStmt{
Label: "",
}
expected := "continue ()"
assert.Equal(t, expected, continueStmt.GetPP())
})

t.Run("ToString with label", func(t *testing.T) {
continueStmt := &ContinueStmt{
Label: "innerLoop",
}
expected := "continue (innerLoop)"
assert.Equal(t, expected, continueStmt.ToString())
})

t.Run("ToString without label", func(t *testing.T) {
continueStmt := &ContinueStmt{
Label: "",
}
expected := "continue ()"
assert.Equal(t, expected, continueStmt.ToString())
})

t.Run("hasLabel with label", func(t *testing.T) {
continueStmt := &ContinueStmt{
Label: "loop1",
}
assert.True(t, continueStmt.hasLabel())
})

t.Run("hasLabel without label", func(t *testing.T) {
continueStmt := &ContinueStmt{
Label: "",
}
assert.False(t, continueStmt.hasLabel())
})

t.Run("GetLabel with label", func(t *testing.T) {
continueStmt := &ContinueStmt{
Label: "loop2",
}
assert.Equal(t, "loop2", continueStmt.GetLabel())
})

t.Run("GetLabel without label", func(t *testing.T) {
continueStmt := &ContinueStmt{
Label: "",
}
assert.Equal(t, "", continueStmt.GetLabel())
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ protected void onCreate(Bundle savedInstanceState) {
if (savedInstanceState == null) {

movieDetailFragment fragment = new movieDetailFragment();
break outlabel;
continue outlabel;
fragment.setMovieData(moviegeneralModal);
getSupportFragmentManager().beginTransaction()
.add(R.id.movie_detail_container, fragment)
Expand Down

0 comments on commit 67efb23

Please sign in to comment.