Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(543)

Delta Between Two Patch Sets: debug/dwarf/type.go

Issue 116730043: code review 116730043: ogle/debug/dwarf: add SliceType, StringType, MapType (Closed)
Left Patch Set: Created 9 years, 8 months ago
Right Patch Set: diff -r 4f0a7455f8e0 https://code.google.com/p/ogle Created 9 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « debug/dwarf/const.go ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2009 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // DWARF type information structures. 5 // DWARF type information structures.
6 // The format is heavily biased toward C, but for simplicity 6 // The format is heavily biased toward C, but for simplicity
7 // the String methods use a pseudo-Go syntax. 7 // the String methods use a pseudo-Go syntax.
8 8
9 package dwarf 9 package dwarf
10 10
11 import "strconv" 11 import (
12 » "reflect"
13 » "strconv"
14 )
12 15
13 // A Type conventionally represents a pointer to any of the 16 // A Type conventionally represents a pointer to any of the
14 // specific Type structures (CharType, StructType, etc.). 17 // specific Type structures (CharType, StructType, etc.).
15 type Type interface { 18 type Type interface {
16 Common() *CommonType 19 Common() *CommonType
17 String() string 20 String() string
18 Size() int64 21 Size() int64
19 } 22 }
20 23
21 // A CommonType holds fields common to multiple types. 24 // A CommonType holds fields common to multiple types.
22 // If a field is not known or not applicable for a given type, 25 // If a field is not known or not applicable for a given type,
23 // the zero value is used. 26 // the zero value is used.
24 type CommonType struct { 27 type CommonType struct {
25 » ByteSize int64 // size of value of this type, in bytes 28 » ByteSize int64 // size of value of this type, in bytes
26 » Name string // name that can be used to refer to type 29 » Name string // name that can be used to refer to type
30 » ReflectKind reflect.Kind // the reflect kind of the type.
27 } 31 }
28 32
29 func (c *CommonType) Common() *CommonType { return c } 33 func (c *CommonType) Common() *CommonType { return c }
30 34
31 func (c *CommonType) Size() int64 { return c.ByteSize } 35 func (c *CommonType) Size() int64 { return c.ByteSize }
32 36
33 // Basic types 37 // Basic types
34 38
35 // A BasicType holds fields common to all basic types. 39 // A BasicType holds fields common to all basic types.
36 type BasicType struct { 40 type BasicType struct {
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 s += "@" + strconv.FormatInt(f.ByteOffset, 10) 178 s += "@" + strconv.FormatInt(f.ByteOffset, 10)
175 if f.BitSize > 0 { 179 if f.BitSize > 0 {
176 s += " : " + strconv.FormatInt(f.BitSize, 10) 180 s += " : " + strconv.FormatInt(f.BitSize, 10)
177 s += "@" + strconv.FormatInt(f.BitOffset, 10) 181 s += "@" + strconv.FormatInt(f.BitOffset, 10)
178 } 182 }
179 } 183 }
180 s += "}" 184 s += "}"
181 return s 185 return s
182 } 186 }
183 187
188 // A SliceType represents a Go slice type. It looks like a StructType, describin g
189 // the runtime-internal structure, with extra fields.
190 type SliceType struct {
191 StructType
192 ElemType Type
193 }
194
195 func (t *SliceType) String() string {
196 if t.Name != "" {
197 return t.Name
198 }
199 return "[]" + t.ElemType.String()
200 }
201
202 // A StringType represents a Go string type. It looks like a StructType, describ ing
203 // the runtime-internal structure, but we wrap it for neatness.
204 type StringType struct {
205 StructType
206 }
207
208 func (t *StringType) String() string {
209 if t.Name != "" {
210 return t.Name
211 }
212 return "string"
213 }
214
184 // An EnumType represents an enumerated type. 215 // An EnumType represents an enumerated type.
185 // The only indication of its native integer type is its ByteSize 216 // The only indication of its native integer type is its ByteSize
186 // (inside CommonType). 217 // (inside CommonType).
187 type EnumType struct { 218 type EnumType struct {
188 CommonType 219 CommonType
189 EnumName string 220 EnumName string
190 Val []*EnumValue 221 Val []*EnumValue
191 } 222 }
192 223
193 // An EnumValue represents a single enumeration value. 224 // An EnumValue represents a single enumeration value.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 274
244 // A TypedefType represents a named type. 275 // A TypedefType represents a named type.
245 type TypedefType struct { 276 type TypedefType struct {
246 CommonType 277 CommonType
247 Type Type 278 Type Type
248 } 279 }
249 280
250 func (t *TypedefType) String() string { return t.Name } 281 func (t *TypedefType) String() string { return t.Name }
251 282
252 func (t *TypedefType) Size() int64 { return t.Type.Size() } 283 func (t *TypedefType) Size() int64 { return t.Type.Size() }
284
285 // A MapType represents a Go slice type. It looks like a TypedefType, describing
286 // the runtime-internal structure, with extra fields.
287 type MapType struct {
288 TypedefType
289 KeyType Type
290 ElemType Type
291 }
292
293 func (t *MapType) String() string {
294 if t.Name != "" {
295 return t.Name
296 }
297 return "map[" + t.KeyType.String() + "]" + t.ElemType.String()
298 }
253 299
254 // typeReader is used to read from either the info section or the 300 // typeReader is used to read from either the info section or the
255 // types section. 301 // types section.
256 type typeReader interface { 302 type typeReader interface {
257 Seek(Offset) 303 Seek(Offset)
258 Next() (*Entry, error) 304 Next() (*Entry, error)
259 clone() typeReader 305 clone() typeReader
260 offset() Offset 306 offset() Offset
261 } 307 }
262 308
263 // Type reads the type at off in the DWARF ``info'' section. 309 // Type reads the type at off in the DWARF ``info'' section.
264 func (d *Data) Type(off Offset) (Type, error) { 310 func (d *Data) Type(off Offset) (Type, error) {
265 return d.readType("info", d.Reader(), off, d.typeCache) 311 return d.readType("info", d.Reader(), off, d.typeCache)
312 }
313
314 func getKind(e *Entry) reflect.Kind {
315 integer, _ := e.Val(AttrGoKind).(int64)
316 return reflect.Kind(integer)
266 } 317 }
267 318
268 // readType reads a type from r at off of name using and updating a 319 // readType reads a type from r at off of name using and updating a
269 // type cache. 320 // type cache.
270 func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off set]Type) (Type, error) { 321 func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off set]Type) (Type, error) {
271 if t, ok := typeCache[off]; ok { 322 if t, ok := typeCache[off]; ok {
272 return t, nil 323 return t, nil
273 } 324 }
274 r.Seek(off) 325 r.Seek(off)
275 e, err := r.Next() 326 e, err := r.Next()
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 if kid.Children { 368 if kid.Children {
318 nextDepth++ 369 nextDepth++
319 } 370 }
320 if nextDepth > 0 { 371 if nextDepth > 0 {
321 continue 372 continue
322 } 373 }
323 return kid 374 return kid
324 } 375 }
325 } 376 }
326 377
327 » // Get Type referred to by Entry's AttrType field. 378 » // Get Type referred to by Entry's attr.
328 // Set err if error happens. Not having a type is an error. 379 // Set err if error happens. Not having a type is an error.
329 » typeOf := func(e *Entry) Type { 380 » typeOf := func(e *Entry, attr Attr) Type {
330 » » tval := e.Val(AttrType) 381 » » tval := e.Val(attr)
331 var t Type 382 var t Type
332 switch toff := tval.(type) { 383 switch toff := tval.(type) {
333 case Offset: 384 case Offset:
334 if t, err = d.readType(name, r.clone(), toff, typeCache) ; err != nil { 385 if t, err = d.readType(name, r.clone(), toff, typeCache) ; err != nil {
335 return nil 386 return nil
336 } 387 }
337 case uint64: 388 case uint64:
338 if t, err = d.sigToType(toff); err != nil { 389 if t, err = d.sigToType(toff); err != nil {
339 return nil 390 return nil
340 } 391 }
341 default: 392 default:
342 // It appears that no Type means "void". 393 // It appears that no Type means "void".
343 return new(VoidType) 394 return new(VoidType)
344 } 395 }
345 return t 396 return t
346 } 397 }
347 398
348 switch e.Tag { 399 switch e.Tag {
349 case TagArrayType: 400 case TagArrayType:
350 // Multi-dimensional array. (DWARF v2 §5.4) 401 // Multi-dimensional array. (DWARF v2 §5.4)
351 // Attributes: 402 // Attributes:
352 // AttrType:subtype [required] 403 // AttrType:subtype [required]
353 // AttrStrideSize: size in bits of each element of the arra y 404 // AttrStrideSize: size in bits of each element of the arra y
354 // AttrByteSize: size of entire array 405 // AttrByteSize: size of entire array
355 // Children: 406 // Children:
356 // TagSubrangeType or TagEnumerationType giving one dimensi on. 407 // TagSubrangeType or TagEnumerationType giving one dimensi on.
357 // dimensions are in left to right order. 408 // dimensions are in left to right order.
358 t := new(ArrayType) 409 t := new(ArrayType)
410 t.ReflectKind = getKind(e)
359 typ = t 411 typ = t
360 typeCache[off] = t 412 typeCache[off] = t
361 » » if t.Type = typeOf(e); err != nil { 413 » » if t.Type = typeOf(e, AttrType); err != nil {
362 goto Error 414 goto Error
363 } 415 }
364 t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64) 416 t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64)
365 417
366 // Accumulate dimensions, 418 // Accumulate dimensions,
367 ndim := 0 419 ndim := 0
368 for kid := next(); kid != nil; kid = next() { 420 for kid := next(); kid != nil; kid = next() {
369 // TODO(rsc): Can also be TagEnumerationType 421 // TODO(rsc): Can also be TagEnumerationType
370 // but haven't seen that in the wild yet. 422 // but haven't seen that in the wild yet.
371 switch kid.Tag { 423 switch kid.Tag {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 case encUnsignedChar: 480 case encUnsignedChar:
429 typ = new(UcharType) 481 typ = new(UcharType)
430 } 482 }
431 typeCache[off] = typ 483 typeCache[off] = typ
432 t := typ.(interface { 484 t := typ.(interface {
433 Basic() *BasicType 485 Basic() *BasicType
434 }).Basic() 486 }).Basic()
435 t.Name = name 487 t.Name = name
436 t.BitSize, _ = e.Val(AttrBitSize).(int64) 488 t.BitSize, _ = e.Val(AttrBitSize).(int64)
437 t.BitOffset, _ = e.Val(AttrBitOffset).(int64) 489 t.BitOffset, _ = e.Val(AttrBitOffset).(int64)
490 t.ReflectKind = getKind(e)
438 491
439 case TagClassType, TagStructType, TagUnionType: 492 case TagClassType, TagStructType, TagUnionType:
440 // Structure, union, or class type. (DWARF v2 §5.5) 493 // Structure, union, or class type. (DWARF v2 §5.5)
494 // Also Slices and Strings (Go-specific).
441 // Attributes: 495 // Attributes:
442 // AttrName: name of struct, union, or class 496 // AttrName: name of struct, union, or class
443 // AttrByteSize: byte size [required] 497 // AttrByteSize: byte size [required]
444 // AttrDeclaration: if true, struct/union/class is incomple te 498 // AttrDeclaration: if true, struct/union/class is incomple te
499 // AttrGoElem: present for slices only.
445 // Children: 500 // Children:
446 // TagMember to describe one member. 501 // TagMember to describe one member.
447 // AttrName: name of member [required] 502 // AttrName: name of member [required]
448 // AttrType: type of member [required] 503 // AttrType: type of member [required]
449 // AttrByteSize: size in bytes 504 // AttrByteSize: size in bytes
450 // AttrBitOffset: bit offset within bytes for bit f ields 505 // AttrBitOffset: bit offset within bytes for bit f ields
451 // AttrBitSize: bit size for bit fields 506 // AttrBitSize: bit size for bit fields
452 // AttrDataMemberLoc: location within struct [requi red for struct, class] 507 // AttrDataMemberLoc: location within struct [requi red for struct, class]
453 // There is much more to handle C++, all ignored for now. 508 // There is much more to handle C++, all ignored for now.
454 t := new(StructType) 509 t := new(StructType)
455 » » typ = t 510 » » t.ReflectKind = getKind(e)
456 » » typeCache[off] = t 511 » » switch t.ReflectKind {
512 » » case reflect.Slice:
513 » » » slice := new(SliceType)
514 » » » slice.ElemType = typeOf(e, AttrGoElem)
515 » » » t = &slice.StructType
516 » » » typ = slice
517 » » case reflect.String:
518 » » » str := new(StringType)
519 » » » t = &str.StructType
520 » » » typ = str
521 » » default:
522 » » » typ = t
523 » » }
524 » » typeCache[off] = typ
457 switch e.Tag { 525 switch e.Tag {
458 case TagClassType: 526 case TagClassType:
459 t.Kind = "class" 527 t.Kind = "class"
460 case TagStructType: 528 case TagStructType:
461 t.Kind = "struct" 529 t.Kind = "struct"
462 case TagUnionType: 530 case TagUnionType:
463 t.Kind = "union" 531 t.Kind = "union"
464 } 532 }
465 t.StructName, _ = e.Val(AttrName).(string) 533 t.StructName, _ = e.Val(AttrName).(string)
466 t.Incomplete = e.Val(AttrDeclaration) != nil 534 t.Incomplete = e.Val(AttrDeclaration) != nil
467 t.Field = make([]*StructField, 0, 8) 535 t.Field = make([]*StructField, 0, 8)
468 var lastFieldType Type 536 var lastFieldType Type
469 var lastFieldBitOffset int64 537 var lastFieldBitOffset int64
470 for kid := next(); kid != nil; kid = next() { 538 for kid := next(); kid != nil; kid = next() {
471 if kid.Tag == TagMember { 539 if kid.Tag == TagMember {
472 f := new(StructField) 540 f := new(StructField)
473 » » » » if f.Type = typeOf(kid); err != nil { 541 » » » » if f.Type = typeOf(kid, AttrType); err != nil {
474 goto Error 542 goto Error
475 } 543 }
476 switch loc := kid.Val(AttrDataMemberLoc).(type) { 544 switch loc := kid.Val(AttrDataMemberLoc).(type) {
477 case []byte: 545 case []byte:
478 // TODO: Should have original compilatio n 546 // TODO: Should have original compilatio n
479 // unit here, not unknownFormat. 547 // unit here, not unknownFormat.
480 b := makeBuf(d, unknownFormat{}, "locati on", 0, loc) 548 b := makeBuf(d, unknownFormat{}, "locati on", 0, loc)
481 if x := b.uint8(); x != opPlusUconst { 549 if x := b.uint8(); x != opPlusUconst {
482 err = DecodeError{name, kid.Offs et, "unexpected opcode 0x" + strconv.FormatUint(uint64(x), 16)} 550 err = DecodeError{name, kid.Offs et, "unexpected opcode 0x" + strconv.FormatUint(uint64(x), 16)}
483 goto Error 551 goto Error
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 // Final field must be zero width. Fix array le ngth. 585 // Final field must be zero width. Fix array le ngth.
518 zeroArray(lastFieldType) 586 zeroArray(lastFieldType)
519 } 587 }
520 } 588 }
521 589
522 case TagConstType, TagVolatileType, TagRestrictType: 590 case TagConstType, TagVolatileType, TagRestrictType:
523 // Type modifier (DWARF v2 §5.2) 591 // Type modifier (DWARF v2 §5.2)
524 // Attributes: 592 // Attributes:
525 // AttrType: subtype 593 // AttrType: subtype
526 t := new(QualType) 594 t := new(QualType)
595 t.ReflectKind = getKind(e)
527 typ = t 596 typ = t
528 typeCache[off] = t 597 typeCache[off] = t
529 » » if t.Type = typeOf(e); err != nil { 598 » » if t.Type = typeOf(e, AttrType); err != nil {
530 goto Error 599 goto Error
531 } 600 }
532 switch e.Tag { 601 switch e.Tag {
533 case TagConstType: 602 case TagConstType:
534 t.Qual = "const" 603 t.Qual = "const"
535 case TagRestrictType: 604 case TagRestrictType:
536 t.Qual = "restrict" 605 t.Qual = "restrict"
537 case TagVolatileType: 606 case TagVolatileType:
538 t.Qual = "volatile" 607 t.Qual = "volatile"
539 } 608 }
540 609
541 case TagEnumerationType: 610 case TagEnumerationType:
542 // Enumeration type (DWARF v2 §5.6) 611 // Enumeration type (DWARF v2 §5.6)
543 // Attributes: 612 // Attributes:
544 // AttrName: enum name if any 613 // AttrName: enum name if any
545 // AttrByteSize: bytes required to represent largest value 614 // AttrByteSize: bytes required to represent largest value
546 // Children: 615 // Children:
547 // TagEnumerator: 616 // TagEnumerator:
548 // AttrName: name of constant 617 // AttrName: name of constant
549 // AttrConstValue: value of constant 618 // AttrConstValue: value of constant
550 t := new(EnumType) 619 t := new(EnumType)
620 t.ReflectKind = getKind(e)
551 typ = t 621 typ = t
552 typeCache[off] = t 622 typeCache[off] = t
553 t.EnumName, _ = e.Val(AttrName).(string) 623 t.EnumName, _ = e.Val(AttrName).(string)
554 t.Val = make([]*EnumValue, 0, 8) 624 t.Val = make([]*EnumValue, 0, 8)
555 for kid := next(); kid != nil; kid = next() { 625 for kid := next(); kid != nil; kid = next() {
556 if kid.Tag == TagEnumerator { 626 if kid.Tag == TagEnumerator {
557 f := new(EnumValue) 627 f := new(EnumValue)
558 f.Name, _ = kid.Val(AttrName).(string) 628 f.Name, _ = kid.Val(AttrName).(string)
559 f.Val, _ = kid.Val(AttrConstValue).(int64) 629 f.Val, _ = kid.Val(AttrConstValue).(int64)
560 n := len(t.Val) 630 n := len(t.Val)
561 if n >= cap(t.Val) { 631 if n >= cap(t.Val) {
562 val := make([]*EnumValue, n, n*2) 632 val := make([]*EnumValue, n, n*2)
563 copy(val, t.Val) 633 copy(val, t.Val)
564 t.Val = val 634 t.Val = val
565 } 635 }
566 t.Val = t.Val[0 : n+1] 636 t.Val = t.Val[0 : n+1]
567 t.Val[n] = f 637 t.Val[n] = f
568 } 638 }
569 } 639 }
570 640
571 case TagPointerType: 641 case TagPointerType:
572 // Type modifier (DWARF v2 §5.2) 642 // Type modifier (DWARF v2 §5.2)
573 // Attributes: 643 // Attributes:
574 // AttrType: subtype [not required! void* has no AttrType] 644 // AttrType: subtype [not required! void* has no AttrType]
575 // AttrAddrClass: address class [ignored] 645 // AttrAddrClass: address class [ignored]
576 t := new(PtrType) 646 t := new(PtrType)
647 t.ReflectKind = getKind(e)
577 typ = t 648 typ = t
578 typeCache[off] = t 649 typeCache[off] = t
579 if e.Val(AttrType) == nil { 650 if e.Val(AttrType) == nil {
580 t.Type = &VoidType{} 651 t.Type = &VoidType{}
581 break 652 break
582 } 653 }
583 » » t.Type = typeOf(e) 654 » » t.Type = typeOf(e, AttrType)
584 655
585 case TagSubroutineType: 656 case TagSubroutineType:
586 // Subroutine type. (DWARF v2 §5.7) 657 // Subroutine type. (DWARF v2 §5.7)
587 // Attributes: 658 // Attributes:
588 // AttrType: type of return value if any 659 // AttrType: type of return value if any
589 // AttrName: possible name of type [ignored] 660 // AttrName: possible name of type [ignored]
590 // AttrPrototyped: whether used ANSI C prototype [ignored] 661 // AttrPrototyped: whether used ANSI C prototype [ignored]
591 // Children: 662 // Children:
592 // TagFormalParameter: typed parameter 663 // TagFormalParameter: typed parameter
593 // AttrType: type of parameter 664 // AttrType: type of parameter
594 // TagUnspecifiedParameter: final ... 665 // TagUnspecifiedParameter: final ...
595 t := new(FuncType) 666 t := new(FuncType)
667 t.ReflectKind = getKind(e)
596 typ = t 668 typ = t
597 typeCache[off] = t 669 typeCache[off] = t
598 » » if t.ReturnType = typeOf(e); err != nil { 670 » » if t.ReturnType = typeOf(e, AttrType); err != nil {
599 goto Error 671 goto Error
600 } 672 }
601 t.ParamType = make([]Type, 0, 8) 673 t.ParamType = make([]Type, 0, 8)
602 for kid := next(); kid != nil; kid = next() { 674 for kid := next(); kid != nil; kid = next() {
603 var tkid Type 675 var tkid Type
604 switch kid.Tag { 676 switch kid.Tag {
605 default: 677 default:
606 continue 678 continue
607 case TagFormalParameter: 679 case TagFormalParameter:
608 » » » » if tkid = typeOf(kid); err != nil { 680 » » » » if tkid = typeOf(kid, AttrType); err != nil {
609 goto Error 681 goto Error
610 } 682 }
611 case TagUnspecifiedParameters: 683 case TagUnspecifiedParameters:
612 tkid = &DotDotDotType{} 684 tkid = &DotDotDotType{}
613 } 685 }
614 t.ParamType = append(t.ParamType, tkid) 686 t.ParamType = append(t.ParamType, tkid)
615 } 687 }
616 688
617 case TagTypedef: 689 case TagTypedef:
618 // Typedef (DWARF v2 §5.3) 690 // Typedef (DWARF v2 §5.3)
691 // Also maps (Go-specific).
619 // Attributes: 692 // Attributes:
620 // AttrName: name [required] 693 // AttrName: name [required]
621 // AttrType: type definition [required] 694 // AttrType: type definition [required]
695 // AttrGoKey: present for maps only.
696 // AttrElemKey: present for maps only.
622 t := new(TypedefType) 697 t := new(TypedefType)
623 » » typ = t 698 » » t.ReflectKind = getKind(e)
624 » » typeCache[off] = t 699 » » switch t.ReflectKind {
700 » » case reflect.Map:
701 » » » m := new(MapType)
702 » » » m.KeyType = typeOf(e, AttrGoKey)
703 » » » m.ElemType = typeOf(e, AttrGoElem)
704 » » » t = &m.TypedefType
705 » » » typ = m
706 » » default:
707 » » » typ = t
708 » » }
709 » » typeCache[off] = typ
625 t.Name, _ = e.Val(AttrName).(string) 710 t.Name, _ = e.Val(AttrName).(string)
626 » » t.Type = typeOf(e) 711 » » t.Type = typeOf(e, AttrType)
627 } 712 }
628 713
629 if err != nil { 714 if err != nil {
630 goto Error 715 goto Error
631 } 716 }
632 717
633 { 718 {
634 b, ok := e.Val(AttrByteSize).(int64) 719 b, ok := e.Val(AttrByteSize).(int64)
635 if !ok { 720 if !ok {
636 b = -1 721 b = -1
(...skipping 13 matching lines...) Expand all
650 func zeroArray(t Type) { 735 func zeroArray(t Type) {
651 for { 736 for {
652 at, ok := t.(*ArrayType) 737 at, ok := t.(*ArrayType)
653 if !ok { 738 if !ok {
654 break 739 break
655 } 740 }
656 at.Count = 0 741 at.Count = 0
657 t = at.Type 742 t = at.Type
658 } 743 }
659 } 744 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b