|
| 1 | +package qtrel |
| 2 | + |
| 3 | +import ( |
| 4 | + "go/scanner" |
| 5 | + "go/token" |
| 6 | + "log" |
| 7 | + "reflect" |
| 8 | + "strings" |
| 9 | + "unsafe" |
| 10 | + |
| 11 | + "github.com/ianlancetaylor/demangle" |
| 12 | + "github.com/kitech/qt.go/qtrt" |
| 13 | +) |
| 14 | + |
| 15 | +const ulpfx = "_ZN" |
| 16 | +const culpfx = "C_ZN" |
| 17 | + |
| 18 | +/* |
| 19 | +const QStringNew0 = "_ZN7QStringC2Ev" |
| 20 | +//const QStringNew1 = "_ZN7QStringC2EPKc" |
| 21 | +const QStringLength0 = "_ZNK7QString6lengthEv" |
| 22 | +*/ |
| 23 | + |
| 24 | +// no this version, for ctor and static member and c function |
| 25 | +func CC0(mgname string, args ...interface{}) ccret { |
| 26 | + return ccimpl(nil, mgname, args...) |
| 27 | +} |
| 28 | + |
| 29 | +// only return pointer |
| 30 | +func CC0p(mgname string, args ...interface{}) CObject { |
| 31 | + rv := CC0(mgname, args...) |
| 32 | + return CObject(rv.Ptr()) |
| 33 | +} |
| 34 | + |
| 35 | +func ccimpl(cthis unsafe.Pointer, mgname string, args ...interface{}) ccret { |
| 36 | + mgname = ulpfx + mgname |
| 37 | + cmo := cppfilt(mgname) |
| 38 | + argv := convgoargs2c(cmo, args) |
| 39 | + if cthis != nil { |
| 40 | + argv = append([]interface{}{cthis}, argv...) |
| 41 | + _ = argv |
| 42 | + } |
| 43 | + |
| 44 | + rv, err := qtrt.InvokeQtFunc6(mgname, qtrt.FFI_TYPE_UINT64, argv...) |
| 45 | + // log.Printf("rv=%+v err=%v %s\n", rv, err, mgname) |
| 46 | + qtrt.ErrPrint(err) |
| 47 | + return newccret(rv, &mgname, cmo) |
| 48 | +} |
| 49 | + |
| 50 | +func (this CObject) CC0(mgname string, args ...interface{}) ccret { |
| 51 | + return ccimpl(this.Ptr(), mgname, args...) |
| 52 | +} |
| 53 | + |
| 54 | +func (this CObject) CC0p(mgname string, args ...interface{}) CObject { |
| 55 | + rv := ccimpl(this.Ptr(), mgname, args...) |
| 56 | + return rv.Cobj() |
| 57 | +} |
| 58 | + |
| 59 | +func Inherit(cbobj qtrt.CObjectITF, mgname string, fn interface{}) { |
| 60 | + // cthis unsafe.Pointer |
| 61 | + mgname = ulpfx + mgname |
| 62 | + cmo := cppfilt(mgname) |
| 63 | + qtrt.SetAllInheritCallback(cbobj, cmo.mth, fn) |
| 64 | +} |
| 65 | +func (this CObject) Inherit(mgname string, fn interface{}) { |
| 66 | + // qtrt.SetAllInheritCallback(this, "", fn) |
| 67 | + Inherit(this, mgname, fn) |
| 68 | +} |
| 69 | + |
| 70 | +func (this CObject) Connect(signal string, slotfn interface{}) { |
| 71 | + qtrt.Connect(this, signal, slotfn) |
| 72 | +} |
| 73 | +func (this CObject) Disconnect(signal string) { |
| 74 | + qtrt.Disconnect(this, signal) |
| 75 | +} |
| 76 | + |
| 77 | +type CObject uintptr |
| 78 | + |
| 79 | +func (this CObject) GetCthis() unsafe.Pointer { return unsafe.Pointer(this) } |
| 80 | +func (this CObject) SetCthis(cthis unsafe.Pointer) {} |
| 81 | +func (CObject) FromCthis(cthis unsafe.Pointer) CObject { |
| 82 | + return CObject(uintptr(cthis)) |
| 83 | +} |
| 84 | +func (this CObject) Ptr() unsafe.Pointer { return unsafe.Pointer(this) } |
| 85 | + |
| 86 | +// type QObject uintptr |
| 87 | +// type QWidget uintptr |
| 88 | + |
| 89 | +var ccrety = reflect.TypeOf(ccret(0)) |
| 90 | + |
| 91 | +// assert sizeof(ccret) == sizeof(uintptr) |
| 92 | +// TODO how about x86 pointer |
| 93 | +type ccret uint64 |
| 94 | + |
| 95 | +/* |
| 96 | +type ccret struct { |
| 97 | + rv uint64 |
| 98 | + //typ int |
| 99 | +} |
| 100 | +*/ |
| 101 | + |
| 102 | +func newccret(rv uint64, fnsym *string, cmo *cppmethod) ccret { |
| 103 | + return ccret(rv) |
| 104 | + // return ccret{rv} |
| 105 | + //return ccret{rv, 0} |
| 106 | +} |
| 107 | + |
| 108 | +func (this ccret) Int() int { return int(this) } |
| 109 | +func (this ccret) Uint() uint { return uint(this) } |
| 110 | +func (this ccret) I32() int32 { return int32(this) } |
| 111 | +func (this ccret) I64() int64 { return int64(this) } |
| 112 | +func (this ccret) U32() uint32 { return uint32(this) } |
| 113 | +func (this ccret) U64() uint64 { return uint64(this) } |
| 114 | +func (this ccret) F32() float32 { return float32(this) } |
| 115 | +func (this ccret) F64() float64 { return float64(this) } |
| 116 | +func (this ccret) Ptr() unsafe.Pointer { return unsafe.Pointer(uintptr(this)) } |
| 117 | +func (this ccret) Uptr() uintptr { return uintptr(this) } |
| 118 | +func (this ccret) Bool() bool { return this != 0 } |
| 119 | +func (this ccret) Strc() string { |
| 120 | + // char* => string |
| 121 | + return qtrt.GoString(this.Ptr()) |
| 122 | +} |
| 123 | +func (this ccret) Strq() string { |
| 124 | + // QString => string |
| 125 | + ba := this.Cobj().CC0(QStringToUtf8) |
| 126 | + rv := ba.Cobj().CC0(QByteArrayData) |
| 127 | + return rv.Strc() |
| 128 | +} |
| 129 | +func (this ccret) Cobj() CObject { return CObject(this) } |
| 130 | + |
| 131 | +// for Qt multiple inherit |
| 132 | +func (this ccret) Cobj2() CObject { |
| 133 | + return CObject(this.Uptr() + unsafe.Sizeof(uintptr(0))) |
| 134 | +} |
| 135 | + |
| 136 | +func convgoargs2c(cmo *cppmethod, args []interface{}) []interface{} { |
| 137 | + var argv []interface{} |
| 138 | + if len(args) != cmo.argc() { |
| 139 | + log.Printf("WARN argc not match want %d have %d when call %s.%s\n", |
| 140 | + cmo.argc(), len(args), cmo.cls, cmo.mth) |
| 141 | + } |
| 142 | + for idx, arg := range args { |
| 143 | + val := convgoarg2c(cmo, idx, arg) |
| 144 | + argv = append(argv, val) |
| 145 | + } |
| 146 | + // log.Println("argc/want", len(argv), cmo.argc(), ":", argv) |
| 147 | + return argv |
| 148 | +} |
| 149 | + |
| 150 | +func convgoarg2c(cmo *cppmethod, idx int, argx interface{}) interface{} { |
| 151 | + var rv interface{} = argx |
| 152 | + |
| 153 | + argty := reflect.TypeOf(argx) |
| 154 | + argval := reflect.ValueOf(argx) |
| 155 | + if false { |
| 156 | + log.Println(argty, argval) |
| 157 | + } |
| 158 | + |
| 159 | + cppty := cmo.types[idx] |
| 160 | + if argty == nil { |
| 161 | + if argx == nil { |
| 162 | + rv = unsafe.Pointer(nil) |
| 163 | + return rv |
| 164 | + } |
| 165 | + } |
| 166 | + switch argty.Kind() { |
| 167 | + case reflect.Invalid: |
| 168 | + log.Println("TODO", cmo.cls, cmo.mth) |
| 169 | + case reflect.String: |
| 170 | + // which one? // => QString // => charptr |
| 171 | + tval := argx.(string) |
| 172 | + if cppty == "char *" { |
| 173 | + rv = unsafe.Pointer(nil) |
| 174 | + // val1 := C.CString(arg.(string)) |
| 175 | + // val2 := unsafe.Pointer(val1) |
| 176 | + val1 := []byte(tval) |
| 177 | + if len(val1) > 0 { |
| 178 | + val2 := unsafe.Pointer(&val1[0]) // works |
| 179 | + rv = val2 |
| 180 | + } |
| 181 | + } else if strings.HasPrefix(cppty, "QString") { |
| 182 | + val1 := CC0(QStringNew5, tval) |
| 183 | + rv = val1.Ptr() |
| 184 | + } |
| 185 | + case reflect.Slice: |
| 186 | + if argty.Elem().Kind() == reflect.String { |
| 187 | + rv = qtrt.StringSliceToCCharPP(argx.([]string)) |
| 188 | + // log.Println("converted", argty, arg) |
| 189 | + } |
| 190 | + case reflect.Int: |
| 191 | + if cmo.argisref(idx) { // fix int& |
| 192 | + rvp := reflect.New(argty) |
| 193 | + rvp.Elem().Set(argval) |
| 194 | + rv = unsafe.Pointer(rvp.Pointer()) |
| 195 | + } |
| 196 | + case reflect.Bool: // just ok |
| 197 | + case reflect.Uintptr: |
| 198 | + log.Println("wtt", idx, argx) |
| 199 | + case reflect.Struct: |
| 200 | + if argty == ccrety { |
| 201 | + arg := argx.(ccret) |
| 202 | + rv = arg.Ptr() |
| 203 | + } |
| 204 | + default: |
| 205 | + log.Println("wtt", idx, argty, argty.Kind(), argval) |
| 206 | + } |
| 207 | + |
| 208 | + return rv |
| 209 | +} |
| 210 | + |
| 211 | +type cppmethod struct { |
| 212 | + cls string |
| 213 | + mth string |
| 214 | + types []string |
| 215 | + names []string |
| 216 | + isconst bool |
| 217 | +} |
| 218 | + |
| 219 | +func (this *cppmethod) isctor() bool { |
| 220 | + return this.cls != "" && (this.cls == this.mth) |
| 221 | +} |
| 222 | + |
| 223 | +func (this *cppmethod) isdtor() bool { |
| 224 | + return strings.HasPrefix(this.mth, "~") |
| 225 | +} |
| 226 | + |
| 227 | +func (this *cppmethod) ismth() bool { |
| 228 | + return this.cls != "" |
| 229 | +} |
| 230 | + |
| 231 | +func (this *cppmethod) argc() int { return len(this.types) } |
| 232 | +func (this *cppmethod) argisref(idx int) bool { |
| 233 | + return strings.Count(this.types[idx], "&") == 1 |
| 234 | +} |
| 235 | +func (this *cppmethod) argisptr(idx int) bool { |
| 236 | + return strings.Count(this.types[idx], "*") == 1 |
| 237 | +} |
| 238 | + |
| 239 | +func cppfilt(mgname string) *cppmethod { |
| 240 | + cmo := &cppmethod{} |
| 241 | + line, err := demangle.ToString(mgname) |
| 242 | + qtrt.ErrPrint(err) |
| 243 | + // log.Println(mgname, line) |
| 244 | + |
| 245 | + { |
| 246 | + // src := []byte("cos(x) + 1i*sin(x) // Euler") |
| 247 | + src := []byte(line) |
| 248 | + |
| 249 | + // Initialize the scanner. |
| 250 | + var s scanner.Scanner |
| 251 | + fset := token.NewFileSet() // positions are relative to fset |
| 252 | + file := fset.AddFile("", fset.Base(), len(src)) // register input "file" |
| 253 | + s.Init(file, src, nil /* no error handler */, scanner.ScanComments) |
| 254 | + |
| 255 | + var idts []string |
| 256 | + var colon = 0 |
| 257 | + // Repeated calls to Scan yield the token sequence found in the input. |
| 258 | + for { |
| 259 | + pos, tok, lit := s.Scan() |
| 260 | + if tok == token.EOF { |
| 261 | + break |
| 262 | + } |
| 263 | + // fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit) |
| 264 | + switch tok { |
| 265 | + case token.CONST: |
| 266 | + case token.IDENT: |
| 267 | + idts = append(idts, lit) |
| 268 | + case token.COLON: |
| 269 | + colon += 1 |
| 270 | + if colon == 2 { |
| 271 | + cmo.cls = idts[len(idts)-1] |
| 272 | + } |
| 273 | + case token.LPAREN: |
| 274 | + cmo.mth = idts[len(idts)-1] |
| 275 | + idts = []string{} |
| 276 | + case token.RPAREN: |
| 277 | + if len(idts) == 0 { |
| 278 | + break |
| 279 | + } |
| 280 | + tyfld := strings.Join(idts, " ") |
| 281 | + cmo.types = append(cmo.types, tyfld) |
| 282 | + idts = []string{} |
| 283 | + case token.MUL: |
| 284 | + idts = append(idts, tok.String()) |
| 285 | + case token.AND: |
| 286 | + idts = append(idts, tok.String()) |
| 287 | + case token.COMMA: |
| 288 | + if len(idts) == 0 { |
| 289 | + break |
| 290 | + } |
| 291 | + tyfld := strings.Join(idts, " ") |
| 292 | + cmo.types = append(cmo.types, tyfld) |
| 293 | + idts = []string{} |
| 294 | + case token.SEMICOLON: |
| 295 | + case token.LSS: // TODO template<> |
| 296 | + idts = append(idts, tok.String()) |
| 297 | + case token.GTR: |
| 298 | + idts = append(idts, tok.String()) |
| 299 | + default: |
| 300 | + log.Println("wtt", fset.Position(pos), tok, lit, mgname) |
| 301 | + } |
| 302 | + } |
| 303 | + // log.Printf("%#v\n", cmo) |
| 304 | + } |
| 305 | + |
| 306 | + return cmo |
| 307 | +} |
0 commit comments