11package normalizer
22
33import (
4+ "errors"
5+
46 "gopkg.in/bblfsh/sdk.v2/uast"
57 "gopkg.in/bblfsh/sdk.v2/uast/nodes"
68 . "gopkg.in/bblfsh/sdk.v2/uast/transformer"
@@ -15,59 +17,141 @@ var Normalize = Transformers([][]Transformer{
1517 {Mappings (Normalizers ... )},
1618}... )
1719
18- type opArrHasParams struct {
19- origArr Op
20+ var _ Op = opArrHasKeyword {}
21+
22+ type opArrHasKeyword struct {
23+ keyword string
24+ opHas Op
25+ opRest Op
2026}
2127
22- func (op opArrHasParams ) Kinds () nodes.Kind {
28+ func (op opArrHasKeyword ) Kinds () nodes.Kind {
2329 return nodes .KindArray
2430}
2531
26- func (op opArrHasParams ) Check (st * State , n nodes.Node ) (bool , error ) {
32+ func (op opArrHasKeyword ) Check (st * State , n nodes.Node ) (bool , error ) {
2733 arr , ok := n .(nodes.Array )
2834 if ! ok && arr != nil {
2935 return false , nil
3036 }
37+ // find a node with a specified type and drop if from array
38+ // the boolean flag that we pass to a sub-op will indicate
39+ // if we found it or not
40+ for i , n := range arr {
41+ obj , ok := n .(nodes.Object )
42+ if ! ok {
43+ continue
44+ }
45+ v , ok := obj [uast .KeyType ]
46+ if ! ok {
47+ continue
48+ }
49+ typ , ok := v .(nodes.String )
50+ if ! ok || string (typ ) != op .keyword {
51+ continue
52+ }
53+ // found the keyword
54+ if ok , err := op .opHas .Check (st , nodes .Bool (true )); err != nil || ! ok {
55+ return ok , err
56+ }
57+ rest := make (nodes.Array , len (arr )- 1 )
58+ copy (rest , arr [:i ])
59+ copy (rest [i :], arr [i + 1 :])
60+ return op .opRest .Check (st , rest )
61+ }
62+ // not found, default to false
63+ if ok , err := op .opHas .Check (st , nodes .Bool (false )); err != nil || ! ok {
64+ return ok , err
65+ }
66+ return op .opRest .Check (st , n )
67+ }
68+
69+ func (op opArrHasKeyword ) Construct (st * State , n nodes.Node ) (nodes.Node , error ) {
70+ // first, we will need to read the flag from sub-op
71+ // if it's false, we will just pass and array as-is
72+ // if it's true, we will synthesize and append a node to it
3173
32- res , err := op .origArr .Check (st , arr )
74+ v , err := op .opHas .Construct (st , nil )
75+ if err != nil {
76+ return nil , err
77+ }
78+ has , ok := v .(nodes.Bool )
79+ if ! ok {
80+ return nil , ErrUnexpectedType .New (nodes .Bool (false ), v )
81+ }
82+ n , err = op .opRest .Construct (st , n )
3383 if err != nil {
34- return false , err
84+ return nil , err
85+ } else if ! has {
86+ // pass as-is
87+ return n , nil
3588 }
89+ // synthesize the node
3690
37- return res , nil
91+ // TODO(dennwc): synthesize the node once we care about reverse transform
92+ return n , nil
3893}
3994
40- func (op opArrHasParams ) Construct (st * State , n nodes.Node ) (nodes.Node , error ) {
41- arr , err := op .origArr .Construct (st , n )
42- if err != nil || arr == nil {
43- return n , err
44- }
95+ var _ Op = opArrToChain {}
4596
46- arr2 , ok := arr .(nodes.Array )
47- if ! ok && arr2 != nil {
48- return nil , ErrExpectedList .New (arr2 )
49- }
97+ type opArrToChain struct {
98+ opMods Op
99+ opType Op
100+ // TODO(dennwc): maybe whitelist only known modifiers? seen so far:
101+ // - RefKeyword
102+ // - OutKeyword (we should move it to Returns)
103+ }
50104
51- retVal := false
105+ func (op opArrToChain ) Kinds () nodes.Kind {
106+ return nodes .KindObject
107+ }
52108
53- for _ , n := range arr2 {
54- nobj , ok := n .(nodes.Object )
55- if ! ok {
56- return nil , ErrExpectedObject .New (nobj )
57- }
109+ func (op opArrToChain ) Check (st * State , n nodes.Node ) (bool , error ) {
110+ // we assert that the passed node is an object and start
111+ // checking the Type field recursively
112+ // if there is one, we will remove it from the "Type" field
113+ // from current node and append it to an array
114+ // and we repeat it recursively on the value of the "Type" field
115+ var mods nodes.Array
116+
117+ // TODO(dennwc): implement when we will need a reversal
118+ if ok , err := op .opType .Check (st , n ); err != nil || ! ok {
119+ return ok , err
120+ }
121+ return op .opMods .Check (st , mods )
122+ }
58123
59- objType , ok := nobj ["@type" ].(nodes.String )
124+ func (op opArrToChain ) Construct (st * State , n nodes.Node ) (nodes.Node , error ) {
125+ // load two nodes:
126+ // - the first one is an array of modifiers (objects)
127+ // - the second one is a type node
128+ nd , err := op .opMods .Construct (st , nil )
129+ if err != nil {
130+ return nil , err
131+ }
132+ mods , ok := nd .(nodes.Array )
133+ if ! ok {
134+ return nil , ErrUnexpectedType .New (nodes.Array {}, nd )
135+ }
136+ typ , err := op .opType .Construct (st , n )
137+ if err != nil {
138+ return nil , err
139+ }
140+ // we will now use each modifier to construct a chain or a linked list of nodes
141+ // by adding a "Type" field to each modifier, that will point to the current node
142+ for _ , nd := range mods {
143+ mod , ok := nd .(nodes.Object )
60144 if ! ok {
61- return nil , ErrExpectedValue .New (nobj [ "@type" ] )
145+ return nil , ErrUnexpectedType .New (nodes. Object {}, nd )
62146 }
63-
64- if objType == "ParamsKeyword" {
65- retVal = true
66- break
147+ mod = mod .CloneObject ()
148+ if _ , ok := mod ["Type" ]; ok {
149+ return nil , errors .New ("unexpected field in modifier: Type" )
67150 }
151+ mod ["Type" ] = typ
152+ typ = mod
68153 }
69-
70- return nodes .Bool (retVal ), nil
154+ return typ , nil
71155}
72156
73157func funcDefMap (typ string ) Mapping {
@@ -563,7 +647,7 @@ var Normalizers = []Mapping{
563647 "Default" : Var ("def_init" ),
564648 "IsMissing" : Bool (false ),
565649 "IsStructuredTrivia" : Bool (false ),
566- "Modifiers" : Arr (),
650+ "Modifiers" : Arr (), // TODO(dennwc): any cases when it's not empty?
567651 "Type" : Var ("type" ),
568652 },
569653 Obj {
@@ -586,16 +670,27 @@ var Normalizers = []Mapping{
586670 "Default" : Var ("def_init" ),
587671 "IsMissing" : Bool (false ),
588672 "IsStructuredTrivia" : Any (),
589- "Modifiers" : opArrHasParams {origArr : Var ("modifiers" )},
590- "Type" : Var ("type" ),
673+ "Modifiers" : opArrHasKeyword {
674+ keyword : "ParamsKeyword" ,
675+ opHas : Var ("variadic" ),
676+ opRest : opArrHasKeyword {
677+ keyword : "ThisKeyword" ,
678+ opHas : Var ("this" ),
679+ opRest : Var ("rest" ),
680+ },
681+ },
682+ "Type" : Var ("type" ),
591683 },
592684 Obj {
593- "Name" : Var ("name" ),
594- "Type" : Var ("type" ),
685+ "Name" : Var ("name" ),
686+ "Type" : opArrToChain {
687+ opMods : Var ("rest" ),
688+ opType : Var ("type" ),
689+ },
595690 "Init" : Var ("def_init" ),
596- "Variadic" : opArrHasParams { Var ("modifiers" )} ,
691+ "Variadic" : Var ("variadic" ) ,
597692 "MapVariadic" : Bool (false ),
598- "Receiver" : Bool ( false ),
693+ "Receiver" : Var ( "this" ),
599694 },
600695 )),
601696
0 commit comments