parsemxh.mx raw

   1  package main
   2  
   3  import (
   4  	"bytes"
   5  	"unsafe"
   6  )
   7  
   8  type mxhData struct {
   9  	hash  string
  10  	types []mxhType
  11  }
  12  
  13  type mxhType struct {
  14  	name          string
  15  	fields        []mxhField
  16  	hasEncodeTo   bool
  17  	hasDecodeFrom bool
  18  }
  19  
  20  type mxhField struct {
  21  	name string
  22  	typ  string
  23  }
  24  
  25  var handles []*mxhData
  26  
  27  //export moxie_mxh_parse
  28  func moxie_mxh_parse(dataPtr unsafe.Pointer, dataLen int32) int32 {
  29  	data := unsafe.Slice((*byte)(dataPtr), dataLen)
  30  	lines := bytes.Split(data, "\n")
  31  	if len(lines) == 0 {
  32  		return -1
  33  	}
  34  
  35  	header := bytes.TrimSpace(lines[0])
  36  	if !bytes.HasPrefix(header, "// mxh v1 ") {
  37  		return -1
  38  	}
  39  	hash := bytes.TrimSpace(header[10:])
  40  	if len(hash) == 0 {
  41  		return -1
  42  	}
  43  
  44  	m := &mxhData{hash: hash}
  45  	curIdx := int32(-1)
  46  
  47  	for i := 1; i < len(lines); i++ {
  48  		line := bytes.TrimSpace(lines[i])
  49  		if len(line) == 0 || bytes.HasPrefix(line, "//") {
  50  			continue
  51  		}
  52  
  53  		if bytes.HasPrefix(line, "type ") && bytes.HasSuffix(line, " struct {") {
  54  			name := bytes.TrimSpace(line[5 : len(line)-9])
  55  			m.types = append(m.types, mxhType{name: name})
  56  			curIdx = int32(len(m.types) - 1)
  57  			continue
  58  		}
  59  
  60  		if line == "}" {
  61  			curIdx = -1
  62  			continue
  63  		}
  64  
  65  		if bytes.HasPrefix(line, "func (") && bytes.Contains(line, ") EncodeTo(") {
  66  			if curIdx == -1 {
  67  				start := bytes.IndexByte(line, '(')
  68  				end := bytes.IndexByte(line, ')')
  69  				if start >= 0 && end > start+1 {
  70  					name := bytes.TrimSpace(line[start+1 : end])
  71  					for j := range m.types {
  72  						if m.types[j].name == name {
  73  							m.types[j].hasEncodeTo = true
  74  							break
  75  						}
  76  					}
  77  				}
  78  			} else {
  79  				m.types[curIdx].hasEncodeTo = true
  80  				curIdx = -1
  81  			}
  82  			continue
  83  		}
  84  
  85  		if bytes.HasPrefix(line, "func (*") && bytes.Contains(line, ") DecodeFrom(") {
  86  			start := bytes.Index(line, "(*")
  87  			end := bytes.IndexByte(line, ')')
  88  			if start >= 0 && end > start+2 {
  89  				name := bytes.TrimSpace(line[start+2 : end])
  90  				for j := range m.types {
  91  					if m.types[j].name == name {
  92  						m.types[j].hasDecodeFrom = true
  93  						break
  94  					}
  95  				}
  96  			}
  97  			continue
  98  		}
  99  
 100  		if curIdx >= 0 {
 101  			parts := bytes.Fields(line)
 102  			if len(parts) == 2 {
 103  				m.types[curIdx].fields = append(m.types[curIdx].fields, mxhField{
 104  					name: parts[0],
 105  					typ:  parts[1],
 106  				})
 107  			}
 108  		}
 109  	}
 110  
 111  	handles = append(handles, m)
 112  	return int32(len(handles) - 1)
 113  }
 114  
 115  func copyToOut(s string, outPtr unsafe.Pointer, outCap int32) int32 {
 116  	n := int32(len(s))
 117  	if n > outCap {
 118  		n = outCap
 119  	}
 120  	out := unsafe.Slice((*byte)(outPtr), outCap)
 121  	copy(out[:n], s)
 122  	return n
 123  }
 124  
 125  func validHandle(handle int32) *mxhData {
 126  	if handle < 0 || handle >= int32(len(handles)) {
 127  		return nil
 128  	}
 129  	return handles[handle]
 130  }
 131  
 132  //export moxie_mxh_hash
 133  func moxie_mxh_hash(handle int32, outPtr unsafe.Pointer, outCap int32) int32 {
 134  	m := validHandle(handle)
 135  	if m == nil {
 136  		return -1
 137  	}
 138  	return copyToOut(m.hash, outPtr, outCap)
 139  }
 140  
 141  //export moxie_mxh_type_count
 142  func moxie_mxh_type_count(handle int32) int32 {
 143  	m := validHandle(handle)
 144  	if m == nil {
 145  		return -1
 146  	}
 147  	return int32(len(m.types))
 148  }
 149  
 150  //export moxie_mxh_type_name
 151  func moxie_mxh_type_name(handle int32, idx int32, outPtr unsafe.Pointer, outCap int32) int32 {
 152  	m := validHandle(handle)
 153  	if m == nil || idx < 0 || idx >= int32(len(m.types)) {
 154  		return -1
 155  	}
 156  	return copyToOut(m.types[idx].name, outPtr, outCap)
 157  }
 158  
 159  //export moxie_mxh_type_field_count
 160  func moxie_mxh_type_field_count(handle int32, idx int32) int32 {
 161  	m := validHandle(handle)
 162  	if m == nil || idx < 0 || idx >= int32(len(m.types)) {
 163  		return -1
 164  	}
 165  	return int32(len(m.types[idx].fields))
 166  }
 167  
 168  //export moxie_mxh_type_field_name
 169  func moxie_mxh_type_field_name(handle int32, tidx int32, fidx int32, outPtr unsafe.Pointer, outCap int32) int32 {
 170  	m := validHandle(handle)
 171  	if m == nil || tidx < 0 || tidx >= int32(len(m.types)) {
 172  		return -1
 173  	}
 174  	t := m.types[tidx]
 175  	if fidx < 0 || fidx >= int32(len(t.fields)) {
 176  		return -1
 177  	}
 178  	return copyToOut(t.fields[fidx].name, outPtr, outCap)
 179  }
 180  
 181  //export moxie_mxh_type_field_type
 182  func moxie_mxh_type_field_type(handle int32, tidx int32, fidx int32, outPtr unsafe.Pointer, outCap int32) int32 {
 183  	m := validHandle(handle)
 184  	if m == nil || tidx < 0 || tidx >= int32(len(m.types)) {
 185  		return -1
 186  	}
 187  	t := m.types[tidx]
 188  	if fidx < 0 || fidx >= int32(len(t.fields)) {
 189  		return -1
 190  	}
 191  	return copyToOut(t.fields[fidx].typ, outPtr, outCap)
 192  }
 193  
 194  //export moxie_mxh_type_has_encode
 195  func moxie_mxh_type_has_encode(handle int32, idx int32) int32 {
 196  	m := validHandle(handle)
 197  	if m == nil || idx < 0 || idx >= int32(len(m.types)) {
 198  		return -1
 199  	}
 200  	if m.types[idx].hasEncodeTo {
 201  		return 1
 202  	}
 203  	return 0
 204  }
 205  
 206  //export moxie_mxh_type_has_decode
 207  func moxie_mxh_type_has_decode(handle int32, idx int32) int32 {
 208  	m := validHandle(handle)
 209  	if m == nil || idx < 0 || idx >= int32(len(m.types)) {
 210  		return -1
 211  	}
 212  	if m.types[idx].hasDecodeFrom {
 213  		return 1
 214  	}
 215  	return 0
 216  }
 217  
 218  //export moxie_mxh_free
 219  func moxie_mxh_free(handle int32) {
 220  	if handle >= 0 && handle < int32(len(handles)) {
 221  		handles[handle] = nil
 222  	}
 223  }
 224  
 225  func main() {}
 226