github.com/jhump/protocompile@v0.0.0-20221021153901-4f6f732835e8/ast/service.go (about) 1 package ast 2 3 import "fmt" 4 5 // ServiceNode represents a service declaration. Example: 6 // 7 // service Foo { 8 // rpc Bar (Baz) returns (Bob); 9 // rpc Frobnitz (stream Parts) returns (Gyzmeaux); 10 // } 11 type ServiceNode struct { 12 compositeNode 13 Keyword *KeywordNode 14 Name *IdentNode 15 OpenBrace *RuneNode 16 Decls []ServiceElement 17 CloseBrace *RuneNode 18 } 19 20 func (*ServiceNode) fileElement() {} 21 22 // NewServiceNode creates a new *ServiceNode. All arguments must be non-nil. 23 // - keyword: The token corresponding to the "service" keyword. 24 // - name: The token corresponding to the service's name. 25 // - openBrace: The token corresponding to the "{" rune that starts the body. 26 // - decls: All declarations inside the service body. 27 // - closeBrace: The token corresponding to the "}" rune that ends the body. 28 func NewServiceNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []ServiceElement, closeBrace *RuneNode) *ServiceNode { 29 if keyword == nil { 30 panic("keyword is nil") 31 } 32 if name == nil { 33 panic("name is nil") 34 } 35 if openBrace == nil { 36 panic("openBrace is nil") 37 } 38 if closeBrace == nil { 39 panic("closeBrace is nil") 40 } 41 children := make([]Node, 0, 4+len(decls)) 42 children = append(children, keyword, name, openBrace) 43 for _, decl := range decls { 44 children = append(children, decl) 45 } 46 children = append(children, closeBrace) 47 48 for _, decl := range decls { 49 switch decl := decl.(type) { 50 case *OptionNode, *RPCNode, *EmptyDeclNode: 51 default: 52 panic(fmt.Sprintf("invalid ServiceElement type: %T", decl)) 53 } 54 } 55 56 return &ServiceNode{ 57 compositeNode: compositeNode{ 58 children: children, 59 }, 60 Keyword: keyword, 61 Name: name, 62 OpenBrace: openBrace, 63 Decls: decls, 64 CloseBrace: closeBrace, 65 } 66 } 67 68 // ServiceElement is an interface implemented by all AST nodes that can 69 // appear in the body of a service declaration. 70 type ServiceElement interface { 71 Node 72 serviceElement() 73 } 74 75 var _ ServiceElement = (*OptionNode)(nil) 76 var _ ServiceElement = (*RPCNode)(nil) 77 var _ ServiceElement = (*EmptyDeclNode)(nil) 78 79 // RPCDeclNode is a placeholder interface for AST nodes that represent RPC 80 // declarations. This allows NoSourceNode to be used in place of *RPCNode 81 // for some usages. 82 type RPCDeclNode interface { 83 Node 84 GetName() Node 85 GetInputType() Node 86 GetOutputType() Node 87 } 88 89 var _ RPCDeclNode = (*RPCNode)(nil) 90 var _ RPCDeclNode = NoSourceNode{} 91 92 // RPCNode represents an RPC declaration. Example: 93 // 94 // rpc Foo (Bar) returns (Baz); 95 type RPCNode struct { 96 compositeNode 97 Keyword *KeywordNode 98 Name *IdentNode 99 Input *RPCTypeNode 100 Returns *KeywordNode 101 Output *RPCTypeNode 102 Semicolon *RuneNode 103 OpenBrace *RuneNode 104 Decls []RPCElement 105 CloseBrace *RuneNode 106 } 107 108 func (n *RPCNode) serviceElement() {} 109 110 // NewRPCNode creates a new *RPCNode with no body. All arguments must be non-nil. 111 // - keyword: The token corresponding to the "rpc" keyword. 112 // - name: The token corresponding to the RPC's name. 113 // - input: The token corresponding to the RPC input message type. 114 // - returns: The token corresponding to the "returns" keyword that precedes the output type. 115 // - output: The token corresponding to the RPC output message type. 116 // - semicolon: The token corresponding to the ";" rune that ends the declaration. 117 func NewRPCNode(keyword *KeywordNode, name *IdentNode, input *RPCTypeNode, returns *KeywordNode, output *RPCTypeNode, semicolon *RuneNode) *RPCNode { 118 if keyword == nil { 119 panic("keyword is nil") 120 } 121 if name == nil { 122 panic("name is nil") 123 } 124 if input == nil { 125 panic("input is nil") 126 } 127 if returns == nil { 128 panic("returns is nil") 129 } 130 if output == nil { 131 panic("output is nil") 132 } 133 if semicolon == nil { 134 panic("semicolon is nil") 135 } 136 children := []Node{keyword, name, input, returns, output, semicolon} 137 return &RPCNode{ 138 compositeNode: compositeNode{ 139 children: children, 140 }, 141 Keyword: keyword, 142 Name: name, 143 Input: input, 144 Returns: returns, 145 Output: output, 146 Semicolon: semicolon, 147 } 148 } 149 150 // NewRPCNodeWithBody creates a new *RPCNode that includes a body (and possibly 151 // options). All arguments must be non-nil. 152 // - keyword: The token corresponding to the "rpc" keyword. 153 // - name: The token corresponding to the RPC's name. 154 // - input: The token corresponding to the RPC input message type. 155 // - returns: The token corresponding to the "returns" keyword that precedes the output type. 156 // - output: The token corresponding to the RPC output message type. 157 // - openBrace: The token corresponding to the "{" rune that starts the body. 158 // - decls: All declarations inside the RPC body. 159 // - closeBrace: The token corresponding to the "}" rune that ends the body. 160 func NewRPCNodeWithBody(keyword *KeywordNode, name *IdentNode, input *RPCTypeNode, returns *KeywordNode, output *RPCTypeNode, openBrace *RuneNode, decls []RPCElement, closeBrace *RuneNode) *RPCNode { 161 if keyword == nil { 162 panic("keyword is nil") 163 } 164 if name == nil { 165 panic("name is nil") 166 } 167 if input == nil { 168 panic("input is nil") 169 } 170 if returns == nil { 171 panic("returns is nil") 172 } 173 if output == nil { 174 panic("output is nil") 175 } 176 if openBrace == nil { 177 panic("openBrace is nil") 178 } 179 if closeBrace == nil { 180 panic("closeBrace is nil") 181 } 182 children := make([]Node, 0, 7+len(decls)) 183 children = append(children, keyword, name, input, returns, output, openBrace) 184 for _, decl := range decls { 185 children = append(children, decl) 186 } 187 children = append(children, closeBrace) 188 189 for _, decl := range decls { 190 switch decl := decl.(type) { 191 case *OptionNode, *EmptyDeclNode: 192 default: 193 panic(fmt.Sprintf("invalid RPCElement type: %T", decl)) 194 } 195 } 196 197 return &RPCNode{ 198 compositeNode: compositeNode{ 199 children: children, 200 }, 201 Keyword: keyword, 202 Name: name, 203 Input: input, 204 Returns: returns, 205 Output: output, 206 OpenBrace: openBrace, 207 Decls: decls, 208 CloseBrace: closeBrace, 209 } 210 } 211 212 func (n *RPCNode) GetName() Node { 213 return n.Name 214 } 215 216 func (n *RPCNode) GetInputType() Node { 217 return n.Input.MessageType 218 } 219 220 func (n *RPCNode) GetOutputType() Node { 221 return n.Output.MessageType 222 } 223 224 // RPCElement is an interface implemented by all AST nodes that can 225 // appear in the body of an rpc declaration (aka method). 226 type RPCElement interface { 227 Node 228 methodElement() 229 } 230 231 var _ RPCElement = (*OptionNode)(nil) 232 var _ RPCElement = (*EmptyDeclNode)(nil) 233 234 // RPCTypeNode represents the declaration of a request or response type for an 235 // RPC. Example: 236 // 237 // (stream foo.Bar) 238 type RPCTypeNode struct { 239 compositeNode 240 OpenParen *RuneNode 241 Stream *KeywordNode 242 MessageType IdentValueNode 243 CloseParen *RuneNode 244 } 245 246 // NewRPCTypeNode creates a new *RPCTypeNode. All arguments must be non-nil 247 // except stream, which may be nil. 248 // - openParen: The token corresponding to the "(" rune that starts the declaration. 249 // - stream: The token corresponding to the "stream" keyword or nil if not present. 250 // - msgType: The token corresponding to the message type's name. 251 // - closeParen: The token corresponding to the ")" rune that ends the declaration. 252 func NewRPCTypeNode(openParen *RuneNode, stream *KeywordNode, msgType IdentValueNode, closeParen *RuneNode) *RPCTypeNode { 253 if openParen == nil { 254 panic("openParen is nil") 255 } 256 if msgType == nil { 257 panic("msgType is nil") 258 } 259 if closeParen == nil { 260 panic("closeParen is nil") 261 } 262 var children []Node 263 if stream != nil { 264 children = []Node{openParen, stream, msgType, closeParen} 265 } else { 266 children = []Node{openParen, msgType, closeParen} 267 } 268 269 return &RPCTypeNode{ 270 compositeNode: compositeNode{ 271 children: children, 272 }, 273 OpenParen: openParen, 274 Stream: stream, 275 MessageType: msgType, 276 CloseParen: closeParen, 277 } 278 }