Commit d0a883df authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 346454a3
...@@ -2,6 +2,12 @@ ...@@ -2,6 +2,12 @@
package neo package neo
// XXX move imports out of here
import (
"encoding/binary"
"math"
)
const ( const (
PROTOCOL_VERSION = 8 PROTOCOL_VERSION = 8
...@@ -40,7 +46,7 @@ const ( ...@@ -40,7 +46,7 @@ const (
STOPPING_BACKUP STOPPING_BACKUP
) )
type NodeType int type NodeType int32
const ( const (
MASTER NodeType = iota MASTER NodeType = iota
STORAGE STORAGE
...@@ -99,6 +105,7 @@ type Address struct { ...@@ -99,6 +105,7 @@ type Address struct {
} }
// NOTE if Host == "" -> Port not added to wire (see py.PAddress): // NOTE if Host == "" -> Port not added to wire (see py.PAddress):
/*
func (a *Address) NEOEncode(b []byte) int { func (a *Address) NEOEncode(b []byte) int {
n := string_NEOEncode(a.Host, b[0:]) n := string_NEOEncode(a.Host, b[0:])
if a.Host != "" { if a.Host != "" {
...@@ -118,6 +125,7 @@ func (a *Address) NEODecode(b []byte) int { ...@@ -118,6 +125,7 @@ func (a *Address) NEODecode(b []byte) int {
} }
return n return n
} }
*/
// A SHA1 hash // A SHA1 hash
type Checksum [20]byte type Checksum [20]byte
...@@ -130,23 +138,23 @@ type Float64 float64 ...@@ -130,23 +138,23 @@ type Float64 float64
// NOTE py.None encodes as '\xff' * 8 (-> we use NaN for None) // NOTE py.None encodes as '\xff' * 8 (-> we use NaN for None)
// NOTE '\xff' * 8 represents FP NaN but many other NaN bits representation exist // NOTE '\xff' * 8 represents FP NaN but many other NaN bits representation exist
func (f Float64) NEOEncode(b []byte) int { // func (f Float64) NEOEncode(b []byte) int {
func float64_NEOEncode(f float64, b []byte) {
var fu uint64 var fu uint64
if !math.IsNaN(f) { if !math.IsNaN(f) {
fu = math.Float64Bits(f) fu = math.Float64bits(f)
} else { } else {
// convert all NaNs to canonical \xff * 8 // convert all NaNs to canonical \xff * 8
fu = 1<<64 - 1 fu = 1<<64 - 1
} }
BigEndian.PutUint64(b, fu) binary.BigEndian.PutUint64(b, fu)
return 8
} }
func (f *Float64) NEODecode(b []byte) int { //func (f *Float64) NEODecode(b []byte) int {
fu := BigEndian.Uint64(b) func float64_NEODecode(b []byte) float64 {
f *= math.Float64FromBits(fu) fu := binary.BigEndian.Uint64(b)
return 8 return math.Float64frombits(fu)
} }
// NOTE original NodeList = []NodeInfo // NOTE original NodeList = []NodeInfo
...@@ -172,6 +180,7 @@ type RowInfo struct { ...@@ -172,6 +180,7 @@ type RowInfo struct {
/*
// XXX link request <-> answer ? // XXX link request <-> answer ?
// XXX naming -> PktHeader ? // XXX naming -> PktHeader ?
type PktHead struct { type PktHead struct {
...@@ -179,6 +188,7 @@ type PktHead struct { ...@@ -179,6 +188,7 @@ type PktHead struct {
MsgCode be16 MsgCode be16
Len be32 // whole packet length (including header) Len be32 // whole packet length (including header)
} }
*/
// TODO generate .Encode() / .Decode() // TODO generate .Encode() / .Decode()
......
...@@ -18,8 +18,10 @@ ...@@ -18,8 +18,10 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"go/ast" "go/ast"
"go/importer"
"go/parser" "go/parser"
"go/token" "go/token"
"go/types" "go/types"
...@@ -40,33 +42,40 @@ var info = &types.Info{ ...@@ -40,33 +42,40 @@ var info = &types.Info{
} }
// complete position of a node // complete position of a node
func pos(n ast.Node) { func pos(n ast.Node) token.Position {
return fset.Position(n.Pos()) return fset.Position(n.Pos())
} }
func main() { func main() {
typeMap := map[string]*PacketType{} // XXX needed ? log.SetFlags(0)
//typeMap := map[string]*PacketType{} // XXX needed ?
// go through proto.go and collect packets type definitions // go through proto.go and collect packets type definitions
var mode parser.Mode = 0 // parser.Trace var mode parser.Mode = 0 // parser.Trace
f, err := parser.ParseFile(fset, "proto.go", nil, mode) var fv []*ast.File
if err != nil { for _, src := range []string{"proto.go", "neo.go"} {
log.Fatal(err) // parse error f, err := parser.ParseFile(fset, src, nil, mode)
if err != nil {
log.Fatalf("parse: %v", err)
}
fv = append(fv, f)
} }
conf := types.Config{} conf := types.Config{Importer: importer.Default()}
pkg, err := conf.Check("proto", fset, []*ast.File{f}, info) _, err := conf.Check("neo", fset, fv, info)
if err != nil { if err != nil {
log.Fatal(err) // typecheck error log.Fatalf("typecheck: %v", err)
} }
ncode := 0 //ncode := 0
//ast.Print(fset, f) //ast.Print(fset, f)
//return //return
f := fv[0] // proto.go comes first
for _, decl := range f.Decls { for _, decl := range f.Decls {
// we look for types (which can be only under GenDecl) // we look for types (which can be only under GenDecl)
gendecl, ok := decl.(*ast.GenDecl) gendecl, ok := decl.(*ast.GenDecl)
...@@ -76,18 +85,21 @@ func main() { ...@@ -76,18 +85,21 @@ func main() {
for _, spec := range gendecl.Specs { for _, spec := range gendecl.Specs {
typespec := spec.(*ast.TypeSpec) // must be because tok = TYPE typespec := spec.(*ast.TypeSpec) // must be because tok = TYPE
typename := typespec.Name.Name //typename := typespec.Name.Name
switch t := typespec.Type.(type) { switch typespec.Type.(type) {
default: default:
// we are only interested in struct types // we are only interested in struct types
continue continue
case *ast.StructType: case *ast.StructType:
//fmt.Printf("\n%s:\n", typename) //fmt.Printf("\n%s:\n", typename)
//continue
//fmt.Println(t) //fmt.Println(t)
//ast.Print(fset, t) //ast.Print(fset, t)
gendecode(typespec)
/*
PacketType{name: typename, msgCode: ncode} PacketType{name: typename, msgCode: ncode}
// if ncode != 0 { // if ncode != 0 {
...@@ -114,6 +126,7 @@ func main() { ...@@ -114,6 +126,7 @@ func main() {
} }
ncode++ ncode++
*/
} }
} }
...@@ -122,23 +135,61 @@ func main() { ...@@ -122,23 +135,61 @@ func main() {
} }
} }
/*
// wiresize returns wire size of a type // wiresize returns wire size of a type
// type must be of fixed size (e.g. not a slice or map) // type must be of fixed size (e.g. not a slice or map)
// XXX ast.Expr -> ? // XXX ast.Expr -> ?
func wiresize(*ast.Expr) int { func wiresize(*ast.Expr) int {
// TODO // TODO
} }
*/
// info about wire decode/encode of a basic type
type basicXXX struct {
wireSize int
decode string
//encode string
}
var basicDecode = map[types.BasicKind]basicXXX {
// %v will be `data[n:n+wireSize]` XXX or `data[n:]` ?
types.Bool: {1, "bool((%v)[0])"},
types.Int8: {1, "int8((%v)[0])"},
types.Int16: {2, "int16(BigEndian.Uint16(%v))"},
types.Int32: {4, "int32(BigEndian.Uint32(%v))"},
types.Int64: {8, "int64(BigEndian.Uint64(%v))"},
types.Uint8: {1, "(%v)[0]"},
types.Uint16: {2, "BigEndian.Uint16(%v)"},
types.Uint32: {4, "BigEndian.Uint32(%v)"},
types.Uint64: {8, "BigEndian.Uint64(%v)"},
types.Float64: {8, "float64_NEODecode(%v)"},
// XXX string ?
}
// bytes.Buffer + bell&whistless
type Buffer struct {
bytes.Buffer
}
func (b *Buffer) Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(b, format, a...)
}
func gendecode(typespec *ast.TypeSpec) string { func gendecode(typespec *ast.TypeSpec) string {
buf := butes.Buffer{} buf := Buffer{}
emitf := buf.Printf
typename := typespec.Name.Name typename := typespec.Name.Name
t := typespec.Type.(*ast.StructType) // must be t := typespec.Type.(*ast.StructType) // must be
fmt.Fprintf(&buf, "func (p *%s) NEODecode(data []byte) int {\n", typename) emitf("func (p *%s) NEODecode(data []byte) int {\n", typename)
n := 0 // current decode pos in data n := 0 // current decode pos in data
for _, fieldv := t.Fields.List { for _, fieldv := range t.Fields.List {
// type B struct { ... } // type B struct { ... }
// //
// type A struct { // type A struct {
...@@ -151,10 +202,50 @@ func gendecode(typespec *ast.TypeSpec) string { ...@@ -151,10 +202,50 @@ func gendecode(typespec *ast.TypeSpec) string {
fieldnamev = []*ast.Ident{fieldv.Type.(*ast.Ident)} fieldnamev = []*ast.Ident{fieldv.Type.(*ast.Ident)}
} }
for fieldname := range fieldnamev { // decode basic fixed types (not string)
switch fieldtype := fieldv.Type.(type) { decodeBasic := func(typ *types.Basic) string {
bdec, ok := basicDecode[typ.Kind()]
if !ok {
log.Fatalf("%v: basic type %v not supported", pos(fieldv), typ)
}
dataptr := fmt.Sprintf("data[%v:]", n)
decoded := fmt.Sprintf(bdec.decode, dataptr)
n += bdec.wireSize
return decoded
}
emitstrbytes := func(fieldname string) {
emitf("{ l := %v", decodeBasic(types.Typ[types.Uint32]))
}
for _, fieldname := range fieldnamev {
fieldtype := info.Types[fieldv.Type].Type
switch u := fieldtype.Underlying().(type) {
// we are processing: <fieldname> <fieldtype> // we are processing: <fieldname> <fieldtype>
// bool, uint32, string, ...
case *types.Basic:
if u.Kind() == types.String {
emitstrbytes(fieldname.Name)
continue
}
emitf("p.%s = %s", fieldname, decodeBasic(u))
case *types.Slice:
// TODO
case *types.Map:
// TODO
// TODO types.Struct
/*
// simple types like uint16 // simple types like uint16
case *ast.Ident: case *ast.Ident:
// TODO // TODO
...@@ -169,10 +260,10 @@ func gendecode(typespec *ast.TypeSpec) string { ...@@ -169,10 +260,10 @@ func gendecode(typespec *ast.TypeSpec) string {
// len u32 // len u32
// [len] items // [len] items
emit("length = Uint32(data[%s:])", n) emitf("length = Uint32(data[%s:])", n)
n += 4 n += 4
emit("for ; length != 0; length-- {") emitf("for ; length != 0; length-- {")
emit("}") emitf("}")
...@@ -180,16 +271,17 @@ func gendecode(typespec *ast.TypeSpec) string { ...@@ -180,16 +271,17 @@ func gendecode(typespec *ast.TypeSpec) string {
case *ast.MapType: case *ast.MapType:
// len u32 // len u32
// [len] key, value // [len] key, value
emit("length = Uint32(data[%s:])", n) emitf("length = Uint32(data[%s:])", n)
n += 4 n += 4
keysize := wiresize(fieldtype.Key) keysize := wiresize(fieldtype.Key)
valsize := wiresize(fieldtype.Value) valsize := wiresize(fieldtype.Value)
// XXX *ast.StructType ? // XXX *ast.StructType ?
*/
default: default:
panic() // TODO log.Fatalf("%v: field %v has unsupported type %v", pos(fieldv), fieldname, fieldtype)
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment