github.com/jmigpin/editor@v1.6.0/core/godebug/stringifyitem.go (about) 1 package godebug 2 3 import ( 4 "fmt" 5 "go/token" 6 "strings" 7 8 "github.com/jmigpin/editor/core/godebug/debug" 9 ) 10 11 func StringifyItem(item debug.Item) string { 12 is := NewItemStringifier() 13 is.stringify(item) 14 return is.b.String() 15 } 16 func StringifyItemFull(item debug.Item) string { 17 is := NewItemStringifier() 18 is.fullStr = true 19 is.stringify(item) 20 return is.b.String() 21 } 22 23 //---------- 24 25 type ItemStringifier struct { 26 b *strings.Builder 27 fullStr bool 28 } 29 30 func NewItemStringifier() *ItemStringifier { 31 is := &ItemStringifier{} 32 is.b = &strings.Builder{} 33 return is 34 } 35 36 func (is *ItemStringifier) p(s string) { 37 is.b.WriteString(s) 38 } 39 40 //---------- 41 42 //func (is *ItemStringifier) captureStringify(item debug.Item) (start, end int, s string) { 43 // start = len(is.Str) 44 // is.stringify(item) 45 // end = len(is.Str) 46 // return start, end, is.Str[start:end] 47 //} 48 49 //func (is *ItemStringifier) stringify(item debug.Item) { 50 //// capture value 51 //start := len(is.Str) 52 //defer func() { 53 // end := len(is.Str) 54 // if is.Offset >= start && is.Offset < end { 55 // s := is.Str[start:end] 56 // if is.OffsetValueString == "" || len(s) < len(is.OffsetValueString) { 57 // is.OffsetValueString = s 58 // } 59 // } 60 //}() 61 62 //is.stringify2(item) 63 //} 64 65 //---------- 66 67 func (is *ItemStringifier) stringify(item debug.Item) { 68 is.stringify2(item) 69 } 70 71 func (is *ItemStringifier) stringify2(item debug.Item) { 72 // NOTE: the string append is done sequentially to allow to detect where the strings are positioned (if later supported) 73 74 //log.Printf("stringifyitem: %T", item) 75 76 switch t := item.(type) { 77 case *debug.ItemValue: 78 if is.fullStr { 79 is.p(t.Str) 80 } else { 81 is.p(debug.SprintCutCheckQuote(20, t.Str)) 82 } 83 84 case *debug.ItemList: // ex: func args list 85 if t == nil { 86 break 87 } 88 for i, e := range t.List { 89 if i > 0 { 90 is.p(", ") 91 } 92 is.stringify(e) 93 } 94 95 case *debug.ItemList2: 96 if t == nil { 97 break 98 } 99 for i, e := range t.List { 100 if i > 0 { 101 is.p("; ") 102 } 103 is.stringify(e) 104 } 105 106 case *debug.ItemAssign: 107 is.stringify(t.Lhs) 108 109 // it's misleading to get a "2 += 1", better to just show "2 = 1" 110 //is.p(" " + token.Token(t.Op).String() + " ") 111 is.p(" ") 112 switch t2 := token.Token(t.Op); t2 { 113 case token.ADD_ASSIGN, token.SUB_ASSIGN, 114 token.MUL_ASSIGN, token.QUO_ASSIGN, 115 token.REM_ASSIGN, 116 token.INC, token.DEC: 117 is.p("=") 118 default: 119 is.p(t2.String()) 120 } 121 is.p(" ") 122 123 is.stringify(t.Rhs) 124 125 case *debug.ItemSend: 126 is.stringify(t.Chan) 127 is.p(" <- ") 128 is.stringify(t.Value) 129 130 case *debug.ItemCallEnter: 131 is.p("=> ") 132 is.stringify(t.Fun) 133 is.p("(") 134 is.stringify(t.Args) 135 is.p(")") 136 case *debug.ItemCall: 137 _ = is.result(t.Result) 138 is.stringify(t.Enter.Fun) 139 is.p("(") 140 is.stringify(t.Enter.Args) 141 is.p(")") 142 143 case *debug.ItemIndex: 144 _ = is.result(t.Result) 145 if t.Expr != nil { 146 //switch t2 := t.Expr.(type) { 147 //case string: 148 // is.p( t2 149 //default: 150 // is.p( "(" 151 // is.stringify(t.Expr) 152 // is.p( ")" 153 //} 154 is.stringify(t.Expr) 155 } 156 is.p("[") 157 if t.Index != nil { 158 is.stringify(t.Index) 159 } 160 is.p("]") 161 162 case *debug.ItemIndex2: 163 _ = is.result(t.Result) 164 if t.Expr != nil { 165 //switch t2 := t.Expr.(type) { 166 //case string: 167 // is.p( t2 168 //default: 169 // is.p( "(" 170 // is.stringify(t.Expr) 171 // is.p( ")" 172 //} 173 is.stringify(t.Expr) 174 } 175 is.p("[") 176 if t.Low != nil { 177 is.stringify(t.Low) 178 } 179 is.p(":") 180 if t.High != nil { 181 is.stringify(t.High) 182 } 183 if t.Slice3 { 184 is.p(":") 185 } 186 if t.Max != nil { 187 is.stringify(t.Max) 188 } 189 is.p("]") 190 191 case *debug.ItemKeyValue: 192 is.stringify(t.Key) 193 is.p(":") 194 is.stringify(t.Value) 195 196 case *debug.ItemSelector: 197 is.p("(") 198 is.stringify(t.X) 199 is.p(").") 200 is.stringify(t.Sel) 201 202 case *debug.ItemTypeAssert: 203 is.stringify(t.Type) 204 is.p("=type(") 205 is.stringify(t.X) 206 is.p(")") 207 208 case *debug.ItemBinary: 209 showRes := is.result(t.Result) 210 if showRes { 211 is.p("(") 212 } 213 is.stringify(t.X) 214 is.p(" " + token.Token(t.Op).String() + " ") 215 is.stringify(t.Y) 216 if showRes { 217 is.p(")") 218 } 219 220 case *debug.ItemUnaryEnter: 221 is.p("=> ") 222 is.p(token.Token(t.Op).String()) 223 is.stringify(t.X) 224 case *debug.ItemUnary: 225 _ = is.result(t.Result) 226 is.p(token.Token(t.Enter.Op).String()) 227 is.stringify(t.Enter.X) 228 229 case *debug.ItemParen: 230 is.p("(") 231 is.stringify(t.X) 232 is.p(")") 233 234 case *debug.ItemLiteral: 235 is.p("{") // other runes: τ, s // ex: A{a:1}, []byte{1,2} 236 if t != nil { 237 is.stringify(t.Fields) 238 } 239 is.p("}") 240 241 case *debug.ItemAnon: 242 is.p("_") 243 244 case *debug.ItemBranch: 245 is.p("#") 246 case *debug.ItemStep: 247 is.p("#") 248 case *debug.ItemLabel: 249 is.p("#") 250 if t.Reason != "" { 251 is.p(" label: " + t.Reason) 252 } 253 case *debug.ItemNotAnn: 254 is.p(fmt.Sprintf("# not annotated: %v", t.Reason)) 255 256 default: 257 is.p(fmt.Sprintf("[TODO:(%T)%v]", item, item)) 258 } 259 } 260 261 //---------- 262 263 func (is *ItemStringifier) result(result debug.Item) bool { 264 if result == nil { 265 return false 266 } 267 268 isList := false 269 if _, ok := result.(*debug.ItemList); ok { 270 isList = true 271 } 272 if isList { 273 is.p("(") 274 } 275 276 is.stringify(result) 277 278 if isList { 279 is.p(")") 280 } 281 282 is.p("=") // other runes: ≡ // nice, but not all fonts have it defined 283 284 return true 285 }