From 0c37bf4911674dc4c4553d76e07dc2a353f50fe3 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Wed, 14 Sep 2016 00:15:26 -0400 Subject: [PATCH] parsing c++ type identifiers rofl kill me --- ent/decoders.go | 2 + ent/type_spec.go | 112 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 ent/type_spec.go diff --git a/ent/decoders.go b/ent/decoders.go index 1c1b814..7eb4bf1 100644 --- a/ent/decoders.go +++ b/ent/decoders.go @@ -37,6 +37,8 @@ func newFieldDecoder(n *Namespace, f *Field) decoder { return entityDecoder(f.class) } + Debug.Printf("type spec: %v", parseTypeName(n, typeName)) + switch { case strings.HasPrefix(typeName, "CHandle"): return decodeVarInt32 diff --git a/ent/type_spec.go b/ent/type_spec.go new file mode 100644 index 0000000..e469bfd --- /dev/null +++ b/ent/type_spec.go @@ -0,0 +1,112 @@ +package ent + +import ( + "fmt" + "strconv" + "strings" +) + +const ( + t_element = iota // a known element class + t_object // c++ object type that is not a known element class + t_array // c++ array type + t_template // c++ template type +) + +// constant identifiers +var cIdents = map[string]int{"MAX_ABILITY_DRAFT_ABILITIES": 48} + +type typeSpec struct { + name string + kind int + size int + template string + member *typeSpec +} + +func (t typeSpec) String() string { + if t.member != nil { + return fmt.Sprintf("{%v %v %v %v %v}", t.name, t.kind, t.size, t.template, *t.member) + } + return fmt.Sprintf("{%v %v %v %v %v}", t.name, t.kind, t.size, t.template, t.member) +} + +func parseTypeName(n *Namespace, s string) typeSpec { + s = strings.TrimSpace(s) + t := typeSpec{name: s} + + if n.HasClass(s) { + t.kind = t_element + return t + } + + // presumably this is some sort of array type + if strings.ContainsRune(s, '[') { + memName, count := parseArrayName(s) + t.kind = t_array + t.size = count + t.member = new(typeSpec) + *t.member = parseTypeName(n, memName) + return t + } + + if strings.ContainsRune(s, '<') { + t.kind = t_template + template, member := parseTemplateName(s) + t.template = template + t.member = new(typeSpec) + *t.member = parseTypeName(n, member) + return t + } + + t.kind = t_object + return t +} + +func parseArrayName(s string) (string, int) { + runes := []rune(s) + if runes[len(runes)-1] != ']' { + panic("invalid array type name: " + s) + } + for i := len(runes) - 2; i >= 0; i-- { + if runes[i] == '[' { + ns := strings.TrimSpace(string(runes[i+1 : len(runes)-1])) + n, err := strconv.Atoi(ns) + if err != nil { + n = cIdents[ns] + if n == 0 { + panic("invalid array type name: " + err.Error()) + } + } + return strings.TrimSpace(string(runes[:i])), n + } + } + panic("invalid array type name: " + s) +} + +func parseTemplateName(s string) (string, string) { + if strings.ContainsRune(s, ',') { + panic("can't handle templates with multiple parameters") + } + + runes := []rune(s) + template := "" + depth := 0 + bracket_start := -1 + for i, r := range runes { + if r == '<' { + if depth == 0 { + bracket_start = i + template = strings.TrimSpace(string(runes[:i])) + } + depth++ + } + if r == '>' { + depth-- + if depth == 0 { + return template, strings.TrimSpace(string(runes[bracket_start+1 : i])) + } + } + } + panic("invalid template type definition: " + s) +}