Skip to content

Commit 0ff0f9f

Browse files
Denys Smirnovdennwc
authored andcommitted
more comments and cleanup
Signed-off-by: Denys Smirnov <[email protected]>
1 parent 88e6742 commit 0ff0f9f

File tree

1 file changed

+76
-34
lines changed

1 file changed

+76
-34
lines changed

driver/normalizer/normalizer.go

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ func (op opArrHasKeyword) Construct(st *State, n nodes.Node) (nodes.Node, error)
100100
// synthesize the node
101101

102102
// TODO(dennwc): synthesize the node once we care about reverse transform
103+
// see https://github.com/bblfsh/sdk/issues/355
103104
return n, nil
104105
}
105106

@@ -126,6 +127,7 @@ func (op opArrToChain) Check(st *State, n nodes.Node) (bool, error) {
126127
var mods nodes.Array
127128

128129
// TODO(dennwc): implement when we will need a reversal
130+
// see https://github.com/bblfsh/sdk/issues/355
129131
if ok, err := op.opType.Check(st, n); err != nil || !ok {
130132
return ok, err
131133
}
@@ -782,6 +784,16 @@ var triviaField = map[string]string{
782784
"CompilationUnit": "Members",
783785
}
784786

787+
// firstWithType returns an index of the first node type of which matches the filter function.
788+
func firstWithType(arr nodes.Array, fnc func(typ string) bool) int {
789+
for i, sub := range arr {
790+
if fnc(uast.TypeOf(sub)) {
791+
return i
792+
}
793+
}
794+
return -1
795+
}
796+
785797
// opMoveTrivias cuts trivia nodes from LeadingTrivia/TrailingTrivia fields
786798
// and wraps the node into uast:Group that contains those trivias.
787799
type opMoveTrivias struct {
@@ -792,18 +804,38 @@ func (op opMoveTrivias) Kinds() nodes.Kind {
792804
return nodes.KindObject
793805
}
794806

807+
// Check implements the logic to move the trivia out of the node into a Group that will
808+
// wrap the trivia and the node itself.
809+
//
810+
// The function is a bit more complex than it should be because there are some edge cases
811+
// where instead of wrapping the node we will add trivia to a specific field of the node.
812+
//
813+
// There are two general cases here that may overlap.
814+
//
815+
// First, some nodes will have a Leading/TrailingTrivia fields. We will remove those fields
816+
// from the node, and will wrap the node itself into a uast:Group with an array consisting
817+
// of (leading trivia + node + trailing trivia).
818+
//
819+
// There are some edge cases here. For example, we don't want to wrap a CompilationUnit nodes
820+
// so we will add trivia nodes to it's Members slice (see triviaField map for all such cases).
821+
//
822+
// But, we can't stop here because the Group will prevent other annotations to match against
823+
// the original node. To fix this, we also try to access few known fields and check if they
824+
// already contain a Group. If it does, we unwrap the node and join its trivia into our
825+
// leading/trailing slice. This is possible because DSL guarantees that transforms always
826+
// happen in DFS order, thus all child nodes were already visited by this transform.
795827
func (op opMoveTrivias) Check(st *State, n nodes.Node) (bool, error) {
796828
obj, ok := n.(nodes.Object)
797829
if !ok {
798830
return false, nil
799831
}
800-
cloned := false
832+
modified := false
801833
leading, ok1 := obj["LeadingTrivia"].(nodes.Array)
802834
trailing, ok2 := obj["TrailingTrivia"].(nodes.Array)
803835
if ok1 || ok2 {
804836
// we saved the leading and trailing trivias, now wipe them from the node
805837
obj = obj.CloneObject()
806-
cloned = true
838+
modified = true
807839
delete(obj, "LeadingTrivia")
808840
delete(obj, "TrailingTrivia")
809841
}
@@ -827,32 +859,34 @@ func (op opMoveTrivias) Check(st *State, n nodes.Node) (bool, error) {
827859
}
828860
// we already joined trivias and the node into a single array,
829861
// so we will have to find its index now
830-
ind := -1
831-
for i, sub := range arr {
832-
if !strings.HasSuffix(uast.TypeOf(sub), "Trivia") {
833-
ind = i
834-
break
835-
}
836-
}
862+
ind := firstWithType(arr, func(typ string) bool {
863+
return !strings.HasSuffix(typ, "Trivia")
864+
})
865+
837866
var node nodes.Node
838867
if ind < 0 {
839868
// cannot determine an index - pretend everything is a leading trivia
840-
// TODO(dennwc): find another way if it happens in practice
869+
// TODO(dennwc): this should not happen in practice, since leading/trailing
870+
// trivias are always attached to a node, and this node should
871+
// be somewhere in this slice
872+
// but future annotations may drop this node, so we will need
873+
// to find a different way of splitting leading and trailing
874+
// trivia if it happens in practice
841875
leading = append(leading.CloneList(), arr...)
842876
} else {
843877
node = arr[ind]
844878
leading = append(leading.CloneList(), arr[:ind]...)
845879
trailing = append(arr[ind+1:len(arr):len(arr)], trailing...)
846880
}
847-
if !cloned {
881+
if !modified {
848882
obj = obj.CloneObject()
849-
cloned = true
883+
modified = true
850884
}
851885
obj[key] = node
852886
}
853887

854888
if len(leading) == 0 && len(trailing) == 0 {
855-
if !cloned {
889+
if !modified {
856890
return false, nil // unmodified
857891
}
858892
// removed the trivia fields
@@ -871,32 +905,41 @@ func (op opMoveTrivias) Check(st *State, n nodes.Node) (bool, error) {
871905
arr = append(arr, trailing...)
872906

873907
obj[field] = arr
874-
} else {
875-
// wrap the node into a uast:Group
876-
arr := make(nodes.Array, 0, len(leading)+1+len(trailing))
877-
arr = append(arr, leading...)
878-
arr = append(arr, obj)
879-
arr = append(arr, trailing...)
908+
return op.sub.Check(st, obj)
909+
}
880910

881-
// TODO(dennwc): it will be nice if we could extract FullSpan position into the Group
882-
group, err := uast.ToNode(uast.Group{})
883-
if err != nil {
884-
return false, err
885-
}
886-
obj = group.(nodes.Object)
887-
obj["Nodes"] = arr
911+
// wrap the node into a uast:Group
912+
arr := make(nodes.Array, 0, len(leading)+1+len(trailing))
913+
arr = append(arr, leading...)
914+
arr = append(arr, obj)
915+
arr = append(arr, trailing...)
916+
917+
// TODO(dennwc): it will be nice if we could extract FullSpan position into the Group
918+
group, err := uast.ToNode(uast.Group{})
919+
if err != nil {
920+
return false, err
888921
}
889922

923+
// note that we overwrite a variable - it was the current node
924+
// and now it is a Group wrapping the current node
925+
obj = group.(nodes.Object)
926+
obj["Nodes"] = arr
890927
return op.sub.Check(st, obj)
891928
}
892929

893930
func (op opMoveTrivias) Construct(st *State, n nodes.Node) (nodes.Node, error) {
894931
// TODO(dennwc): implement when we will need a reversal
932+
// see https://github.com/bblfsh/sdk/issues/355
895933
return op.sub.Construct(st, n)
896934
}
897935

898-
// opMergeGroups find the uast:Group nodes and merges them into a child
936+
// opMergeGroups finds the uast:Group nodes and merges them into a child
899937
// uast:FunctionGroup, if it exists.
938+
//
939+
// This transform is necessary because opMoveTrivias will wrap all nodes that contain trivia
940+
// into a Group node, and the same will happen with MethodDeclaration nodes. But according
941+
// to a UAST schema defined in SDK, the comments (trivia) should be directly inside the
942+
// FunctionGroup node that wraps functions in Semantic mode.
900943
type opMergeGroups struct {
901944
sub Op
902945
}
@@ -905,6 +948,8 @@ func (op opMergeGroups) Kinds() nodes.Kind {
905948
return nodes.KindObject
906949
}
907950

951+
// Check tests if the current node is uast:Group and if it contains a uast:FunctionGroup
952+
// node, it will remove the current node and merge other children into the FunctionGroup.
908953
func (op opMergeGroups) Check(st *State, n nodes.Node) (bool, error) {
909954
group, ok := n.(nodes.Object)
910955
if !ok || uast.TypeOf(group) != typeGroup {
@@ -914,13 +959,9 @@ func (op opMergeGroups) Check(st *State, n nodes.Node) (bool, error) {
914959
if !ok {
915960
return false, errors.New("expected an array in Group.Nodes")
916961
}
917-
ind := -1
918-
for i, sub := range arr {
919-
if uast.TypeOf(sub) == typeFuncGroup {
920-
ind = i
921-
break
922-
}
923-
}
962+
ind := firstWithType(arr, func(typ string) bool {
963+
return typ == typeFuncGroup
964+
})
924965
if ind < 0 {
925966
return false, nil
926967
}
@@ -945,5 +986,6 @@ func (op opMergeGroups) Check(st *State, n nodes.Node) (bool, error) {
945986

946987
func (op opMergeGroups) Construct(st *State, n nodes.Node) (nodes.Node, error) {
947988
// TODO(dennwc): implement when we will need a reversal
989+
// see https://github.com/bblfsh/sdk/issues/355
948990
return op.sub.Construct(st, n)
949991
}

0 commit comments

Comments
 (0)