github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/pattern/pattern.go (about) 1 package pattern 2 3 import ( 4 "fmt" 5 "go/token" 6 "reflect" 7 "strings" 8 ) 9 10 var ( 11 _ Node = Ellipsis{} 12 _ Node = Binding{} 13 _ Node = RangeStmt{} 14 _ Node = AssignStmt{} 15 _ Node = IndexExpr{} 16 _ Node = IndexListExpr{} 17 _ Node = Ident{} 18 _ Node = Builtin{} 19 _ Node = String("") 20 _ Node = Any{} 21 _ Node = ValueSpec{} 22 _ Node = List{} 23 _ Node = GenDecl{} 24 _ Node = BinaryExpr{} 25 _ Node = ForStmt{} 26 _ Node = ArrayType{} 27 _ Node = DeferStmt{} 28 _ Node = MapType{} 29 _ Node = ReturnStmt{} 30 _ Node = SliceExpr{} 31 _ Node = StarExpr{} 32 _ Node = UnaryExpr{} 33 _ Node = SendStmt{} 34 _ Node = SelectStmt{} 35 _ Node = ImportSpec{} 36 _ Node = IfStmt{} 37 _ Node = GoStmt{} 38 _ Node = Field{} 39 _ Node = SelectorExpr{} 40 _ Node = StructType{} 41 _ Node = KeyValueExpr{} 42 _ Node = FuncType{} 43 _ Node = FuncLit{} 44 _ Node = FuncDecl{} 45 _ Node = Token(0) 46 _ Node = ChanType{} 47 _ Node = CallExpr{} 48 _ Node = CaseClause{} 49 _ Node = CommClause{} 50 _ Node = CompositeLit{} 51 _ Node = EmptyStmt{} 52 _ Node = SwitchStmt{} 53 _ Node = TypeSwitchStmt{} 54 _ Node = TypeAssertExpr{} 55 _ Node = TypeSpec{} 56 _ Node = InterfaceType{} 57 _ Node = BranchStmt{} 58 _ Node = IncDecStmt{} 59 _ Node = BasicLit{} 60 _ Node = Nil{} 61 _ Node = Object{} 62 _ Node = Symbol{} 63 _ Node = Not{} 64 _ Node = Or{} 65 _ Node = IntegerLiteral{} 66 _ Node = TrulyConstantExpression{} 67 ) 68 69 type Symbol struct { 70 Name Node 71 } 72 73 type Token token.Token 74 75 type Nil struct { 76 } 77 78 type Ellipsis struct { 79 Elt Node 80 } 81 82 type IncDecStmt struct { 83 X Node 84 Tok Node 85 } 86 87 type BranchStmt struct { 88 Tok Node 89 Label Node 90 } 91 92 type InterfaceType struct { 93 Methods Node 94 } 95 96 type TypeSpec struct { 97 Name Node 98 Type Node 99 } 100 101 type TypeAssertExpr struct { 102 X Node 103 Type Node 104 } 105 106 type TypeSwitchStmt struct { 107 Init Node 108 Assign Node 109 Body Node 110 } 111 112 type SwitchStmt struct { 113 Init Node 114 Tag Node 115 Body Node 116 } 117 118 type EmptyStmt struct { 119 } 120 121 type CompositeLit struct { 122 Type Node 123 Elts Node 124 } 125 126 type CommClause struct { 127 Comm Node 128 Body Node 129 } 130 131 type CaseClause struct { 132 List Node 133 Body Node 134 } 135 136 type CallExpr struct { 137 Fun Node 138 Args Node 139 // XXX handle ellipsis 140 } 141 142 // TODO(dh): add a ChanDir node, and a way of instantiating it. 143 144 type ChanType struct { 145 Dir Node 146 Value Node 147 } 148 149 type FuncDecl struct { 150 Recv Node 151 Name Node 152 Type Node 153 Body Node 154 } 155 156 type FuncLit struct { 157 Type Node 158 Body Node 159 } 160 161 type FuncType struct { 162 Params Node 163 Results Node 164 } 165 166 type KeyValueExpr struct { 167 Key Node 168 Value Node 169 } 170 171 type StructType struct { 172 Fields Node 173 } 174 175 type SelectorExpr struct { 176 X Node 177 Sel Node 178 } 179 180 type Field struct { 181 Names Node 182 Type Node 183 Tag Node 184 } 185 186 type GoStmt struct { 187 Call Node 188 } 189 190 type IfStmt struct { 191 Init Node 192 Cond Node 193 Body Node 194 Else Node 195 } 196 197 type ImportSpec struct { 198 Name Node 199 Path Node 200 } 201 202 type SelectStmt struct { 203 Body Node 204 } 205 206 type ArrayType struct { 207 Len Node 208 Elt Node 209 } 210 211 type DeferStmt struct { 212 Call Node 213 } 214 215 type MapType struct { 216 Key Node 217 Value Node 218 } 219 220 type ReturnStmt struct { 221 Results Node 222 } 223 224 type SliceExpr struct { 225 X Node 226 Low Node 227 High Node 228 Max Node 229 } 230 231 type StarExpr struct { 232 X Node 233 } 234 235 type UnaryExpr struct { 236 Op Node 237 X Node 238 } 239 240 type SendStmt struct { 241 Chan Node 242 Value Node 243 } 244 245 type Binding struct { 246 Name string 247 Node Node 248 249 idx int 250 } 251 252 type RangeStmt struct { 253 Key Node 254 Value Node 255 Tok Node 256 X Node 257 Body Node 258 } 259 260 type AssignStmt struct { 261 Lhs Node 262 Tok Node 263 Rhs Node 264 } 265 266 type IndexExpr struct { 267 X Node 268 Index Node 269 } 270 271 type IndexListExpr struct { 272 X Node 273 Indices Node 274 } 275 276 type Node interface { 277 String() string 278 isNode() 279 } 280 281 type Ident struct { 282 Name Node 283 } 284 285 type Object struct { 286 Name Node 287 } 288 289 type Builtin struct { 290 Name Node 291 } 292 293 type String string 294 295 type Any struct{} 296 297 type ValueSpec struct { 298 Names Node 299 Type Node 300 Values Node 301 } 302 303 type List struct { 304 Head Node 305 Tail Node 306 } 307 308 type GenDecl struct { 309 Tok Node 310 Specs Node 311 } 312 313 type BasicLit struct { 314 Kind Node 315 Value Node 316 } 317 318 // An IntegerLiteral is a constant expression made up of only integer basic literals and the "+" and "-" unary operators. 319 // That is, 0, -4, -+42 are all integer literals, but 1 + 2 is not. 320 type IntegerLiteral struct { 321 Value Node 322 } 323 324 type BinaryExpr struct { 325 X Node 326 Op Node 327 Y Node 328 } 329 330 type ForStmt struct { 331 Init Node 332 Cond Node 333 Post Node 334 Body Node 335 } 336 337 type Or struct { 338 Nodes []Node 339 } 340 341 type Not struct { 342 Node Node 343 } 344 345 // A TrulyConstantExpression is a constant expression that does not make use of any identifiers. 346 // It is constant even under varying build tags. 347 type TrulyConstantExpression struct { 348 Value Node 349 } 350 351 func stringify(n Node) string { 352 v := reflect.ValueOf(n) 353 var parts []string 354 parts = append(parts, v.Type().Name()) 355 for i := 0; i < v.NumField(); i++ { 356 parts = append(parts, fmt.Sprintf("%s", v.Field(i))) 357 } 358 return "(" + strings.Join(parts, " ") + ")" 359 } 360 361 func (stmt AssignStmt) String() string { return stringify(stmt) } 362 func (expr IndexExpr) String() string { return stringify(expr) } 363 func (expr IndexListExpr) String() string { return stringify(expr) } 364 func (id Ident) String() string { return stringify(id) } 365 func (spec ValueSpec) String() string { return stringify(spec) } 366 func (decl GenDecl) String() string { return stringify(decl) } 367 func (lit BasicLit) String() string { return stringify(lit) } 368 func (expr BinaryExpr) String() string { return stringify(expr) } 369 func (stmt ForStmt) String() string { return stringify(stmt) } 370 func (stmt RangeStmt) String() string { return stringify(stmt) } 371 func (typ ArrayType) String() string { return stringify(typ) } 372 func (stmt DeferStmt) String() string { return stringify(stmt) } 373 func (typ MapType) String() string { return stringify(typ) } 374 func (stmt ReturnStmt) String() string { return stringify(stmt) } 375 func (expr SliceExpr) String() string { return stringify(expr) } 376 func (expr StarExpr) String() string { return stringify(expr) } 377 func (expr UnaryExpr) String() string { return stringify(expr) } 378 func (stmt SendStmt) String() string { return stringify(stmt) } 379 func (spec ImportSpec) String() string { return stringify(spec) } 380 func (stmt SelectStmt) String() string { return stringify(stmt) } 381 func (stmt IfStmt) String() string { return stringify(stmt) } 382 func (stmt IncDecStmt) String() string { return stringify(stmt) } 383 func (stmt GoStmt) String() string { return stringify(stmt) } 384 func (field Field) String() string { return stringify(field) } 385 func (expr SelectorExpr) String() string { return stringify(expr) } 386 func (typ StructType) String() string { return stringify(typ) } 387 func (expr KeyValueExpr) String() string { return stringify(expr) } 388 func (typ FuncType) String() string { return stringify(typ) } 389 func (lit FuncLit) String() string { return stringify(lit) } 390 func (decl FuncDecl) String() string { return stringify(decl) } 391 func (stmt BranchStmt) String() string { return stringify(stmt) } 392 func (expr CallExpr) String() string { return stringify(expr) } 393 func (clause CaseClause) String() string { return stringify(clause) } 394 func (typ ChanType) String() string { return stringify(typ) } 395 func (clause CommClause) String() string { return stringify(clause) } 396 func (lit CompositeLit) String() string { return stringify(lit) } 397 func (stmt EmptyStmt) String() string { return stringify(stmt) } 398 func (typ InterfaceType) String() string { return stringify(typ) } 399 func (stmt SwitchStmt) String() string { return stringify(stmt) } 400 func (expr TypeAssertExpr) String() string { return stringify(expr) } 401 func (spec TypeSpec) String() string { return stringify(spec) } 402 func (stmt TypeSwitchStmt) String() string { return stringify(stmt) } 403 func (nil Nil) String() string { return "nil" } 404 func (builtin Builtin) String() string { return stringify(builtin) } 405 func (obj Object) String() string { return stringify(obj) } 406 func (fn Symbol) String() string { return stringify(fn) } 407 func (el Ellipsis) String() string { return stringify(el) } 408 func (not Not) String() string { return stringify(not) } 409 func (lit IntegerLiteral) String() string { return stringify(lit) } 410 func (expr TrulyConstantExpression) String() string { return stringify(expr) } 411 412 func (or Or) String() string { 413 s := "(Or" 414 for _, node := range or.Nodes { 415 s += " " 416 s += node.String() 417 } 418 s += ")" 419 return s 420 } 421 422 func isProperList(l List) bool { 423 if l.Head == nil && l.Tail == nil { 424 return true 425 } 426 switch tail := l.Tail.(type) { 427 case nil: 428 return false 429 case List: 430 return isProperList(tail) 431 default: 432 return false 433 } 434 } 435 436 func (l List) String() string { 437 if l.Head == nil && l.Tail == nil { 438 return "[]" 439 } 440 441 if isProperList(l) { 442 // pretty-print the list 443 var objs []string 444 for l.Head != nil { 445 objs = append(objs, l.Head.String()) 446 l = l.Tail.(List) 447 } 448 return fmt.Sprintf("[%s]", strings.Join(objs, " ")) 449 } 450 451 return fmt.Sprintf("%s:%s", l.Head, l.Tail) 452 } 453 454 func (bind Binding) String() string { 455 if bind.Node == nil { 456 return bind.Name 457 } 458 return fmt.Sprintf("%s@%s", bind.Name, bind.Node) 459 } 460 461 func (s String) String() string { return fmt.Sprintf("%q", string(s)) } 462 463 func (tok Token) String() string { 464 return fmt.Sprintf("%q", strings.ToUpper(token.Token(tok).String())) 465 } 466 467 func (Any) String() string { return "_" } 468 469 func (AssignStmt) isNode() {} 470 func (IndexExpr) isNode() {} 471 func (IndexListExpr) isNode() {} 472 func (Ident) isNode() {} 473 func (ValueSpec) isNode() {} 474 func (GenDecl) isNode() {} 475 func (BasicLit) isNode() {} 476 func (BinaryExpr) isNode() {} 477 func (ForStmt) isNode() {} 478 func (RangeStmt) isNode() {} 479 func (ArrayType) isNode() {} 480 func (DeferStmt) isNode() {} 481 func (MapType) isNode() {} 482 func (ReturnStmt) isNode() {} 483 func (SliceExpr) isNode() {} 484 func (StarExpr) isNode() {} 485 func (UnaryExpr) isNode() {} 486 func (SendStmt) isNode() {} 487 func (ImportSpec) isNode() {} 488 func (SelectStmt) isNode() {} 489 func (IfStmt) isNode() {} 490 func (IncDecStmt) isNode() {} 491 func (GoStmt) isNode() {} 492 func (Field) isNode() {} 493 func (SelectorExpr) isNode() {} 494 func (StructType) isNode() {} 495 func (KeyValueExpr) isNode() {} 496 func (FuncType) isNode() {} 497 func (FuncLit) isNode() {} 498 func (FuncDecl) isNode() {} 499 func (BranchStmt) isNode() {} 500 func (CallExpr) isNode() {} 501 func (CaseClause) isNode() {} 502 func (ChanType) isNode() {} 503 func (CommClause) isNode() {} 504 func (CompositeLit) isNode() {} 505 func (EmptyStmt) isNode() {} 506 func (InterfaceType) isNode() {} 507 func (SwitchStmt) isNode() {} 508 func (TypeAssertExpr) isNode() {} 509 func (TypeSpec) isNode() {} 510 func (TypeSwitchStmt) isNode() {} 511 func (Nil) isNode() {} 512 func (Builtin) isNode() {} 513 func (Object) isNode() {} 514 func (Symbol) isNode() {} 515 func (Ellipsis) isNode() {} 516 func (Or) isNode() {} 517 func (List) isNode() {} 518 func (String) isNode() {} 519 func (Token) isNode() {} 520 func (Any) isNode() {} 521 func (Binding) isNode() {} 522 func (Not) isNode() {} 523 func (IntegerLiteral) isNode() {} 524 func (TrulyConstantExpression) isNode() {}