Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neo
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Kirill Smelkov
neo
Commits
af3ac0d2
Commit
af3ac0d2
authored
Jan 25, 2017
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
d8f0220c
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
49 additions
and
47 deletions
+49
-47
t/neo/protogen.go
t/neo/protogen.go
+49
-47
No files found.
t/neo/protogen.go
View file @
af3ac0d2
...
@@ -33,7 +33,7 @@ maps, ...).
...
@@ -33,7 +33,7 @@ maps, ...).
Top-level generation driver is in generateCodecCode(). It accepts type
Top-level generation driver is in generateCodecCode(). It accepts type
specification and something that performs actual leaf-nodes code generation
specification and something that performs actual leaf-nodes code generation
(CodeGenerator interface). There are 3 particular codegenerators implemented -
(CodeGenerator interface). There are 3 particular codegenerators implemented -
- size
r
, encoder & decoder - to generate each of the needed method functions. XXX naming
- size
CodeGen
, encoder & decoder - to generate each of the needed method functions. XXX naming
The structure of whole process is very similar to what would be happening at
The structure of whole process is very similar to what would be happening at
runtime if marshalling was reflect based, but statically with go/types we don't
runtime if marshalling was reflect based, but statically with go/types we don't
...
@@ -144,7 +144,7 @@ import (
...
@@ -144,7 +144,7 @@ import (
case
*
ast
.
StructType
:
case
*
ast
.
StructType
:
fmt
.
Fprintf
(
&
buf
,
"// %d. %s
\n\n
"
,
pktCode
,
typename
)
fmt
.
Fprintf
(
&
buf
,
"// %d. %s
\n\n
"
,
pktCode
,
typename
)
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
size
r
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
size
CodeGen
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
encoder
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
encoder
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
decoder
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
decoder
{}))
...
@@ -238,7 +238,7 @@ func (b *Buffer) emit(format string, a ...interface{}) {
...
@@ -238,7 +238,7 @@ func (b *Buffer) emit(format string, a ...interface{}) {
fmt
.
Fprintf
(
b
,
format
+
"
\n
"
,
a
...
)
fmt
.
Fprintf
(
b
,
format
+
"
\n
"
,
a
...
)
}
}
// interface of a codegenerator (for size
r
/coder/decoder XXX naming)
// interface of a codegenerator (for size
CodeGen
/coder/decoder XXX naming)
type
CodeGenerator
interface
{
type
CodeGenerator
interface
{
// tell codegen it should generate code for which type & receiver name
// tell codegen it should generate code for which type & receiver name
setFunc
(
recvName
,
typeName
string
,
typ
types
.
Type
)
setFunc
(
recvName
,
typeName
string
,
typ
types
.
Type
)
...
@@ -266,7 +266,7 @@ type CodeGenerator interface {
...
@@ -266,7 +266,7 @@ type CodeGenerator interface {
}
}
// common part of codegenerators
// common part of codegenerators
type
commonCode
r
struct
{
type
commonCode
Gen
struct
{
recvName
string
// receiver/type for top-level func
recvName
string
// receiver/type for top-level func
typeName
string
// or empty
typeName
string
// or empty
typ
types
.
Type
typ
types
.
Type
...
@@ -274,14 +274,14 @@ type commonCoder struct {
...
@@ -274,14 +274,14 @@ type commonCoder struct {
varUsed
map
[
string
]
bool
// whether a variable was used
varUsed
map
[
string
]
bool
// whether a variable was used
}
}
func
(
c
*
commonCode
r
)
setFunc
(
recvName
,
typeName
string
,
typ
types
.
Type
)
{
func
(
c
*
commonCode
Gen
)
setFunc
(
recvName
,
typeName
string
,
typ
types
.
Type
)
{
c
.
recvName
=
recvName
c
.
recvName
=
recvName
c
.
typeName
=
typeName
c
.
typeName
=
typeName
c
.
typ
=
typ
c
.
typ
=
typ
}
}
// get variable for varname (and automatically mark var as used)
// get variable for varname (and automatically mark var as used)
func
(
c
*
commonCode
r
)
var_
(
varname
string
)
string
{
func
(
c
*
commonCode
Gen
)
var_
(
varname
string
)
string
{
if
c
.
varUsed
==
nil
{
if
c
.
varUsed
==
nil
{
c
.
varUsed
=
make
(
map
[
string
]
bool
)
c
.
varUsed
=
make
(
map
[
string
]
bool
)
}
}
...
@@ -290,7 +290,7 @@ func (c *commonCoder) var_(varname string) string {
...
@@ -290,7 +290,7 @@ func (c *commonCoder) var_(varname string) string {
}
}
// information about symbolic size
// information about symbolic size
// consists of numeric & symbolic parts
// consists of numeric & symbolic
expression
parts
// size is num + expr1 + expr2 + ...
// size is num + expr1 + expr2 + ...
type
SymSize
struct
{
type
SymSize
struct
{
num
int
// numeric part of size
num
int
// numeric part of size
...
@@ -323,6 +323,7 @@ func (s *SymSize) String() string {
...
@@ -323,6 +323,7 @@ func (s *SymSize) String() string {
return
sizeStr
return
sizeStr
}
}
// expression part of size (without numeric part)
func
(
s
*
SymSize
)
ExprString
()
string
{
func
(
s
*
SymSize
)
ExprString
()
string
{
return
strings
.
Join
(
s
.
exprv
,
" + "
)
return
strings
.
Join
(
s
.
exprv
,
" + "
)
}
}
...
@@ -331,21 +332,27 @@ func (s *SymSize) IsZero() bool {
...
@@ -331,21 +332,27 @@ func (s *SymSize) IsZero() bool {
return
s
.
num
==
0
&&
len
(
s
.
exprv
)
==
0
return
s
.
num
==
0
&&
len
(
s
.
exprv
)
==
0
}
}
func
(
s
*
SymSize
)
Reset
()
{
*
s
=
SymSize
{}
}
// sizer generates code to compute encoded size of a packet
// sizeCodeGen generates code to compute encoded size of a packet
type
sizer
struct
{
// XXX naming ok?
// XXX -> Gen_NEOEncodedLen ?
type
sizeCodeGen
struct
{
Buffer
// buffer for code
Buffer
// buffer for code
size
SymSize
size
SymSize
// currently accumulated packet size
commonCode
r
commonCode
Gen
}
}
// encoder generates code to encode a packet
// encoder generates code to encode a packet
type
encoder
struct
{
type
encoder
struct
{
Buffer
// XXX
Buffer
// XXX
n
int
n
int
// current write position in data
commonCode
r
commonCode
Gen
}
}
// decoder generates code to decode a packet
// decoder generates code to decode a packet
...
@@ -355,7 +362,7 @@ type decoder struct {
...
@@ -355,7 +362,7 @@ type decoder struct {
buf
Buffer
buf
Buffer
bufCur
Buffer
bufCur
Buffer
// current
decode
position in data.
// current
read
position in data.
n
int
n
int
// size that will be checked for overflow at current overflow check point
// size that will be checked for overflow at current overflow check point
...
@@ -364,15 +371,15 @@ type decoder struct {
...
@@ -364,15 +371,15 @@ type decoder struct {
// whether overflow was already checked for current decodings
// whether overflow was already checked for current decodings
overflowChecked
bool
overflowChecked
bool
commonCode
r
commonCode
Gen
}
}
var
_
CodeGenerator
=
(
*
size
r
)(
nil
)
var
_
CodeGenerator
=
(
*
size
CodeGen
)(
nil
)
var
_
CodeGenerator
=
(
*
encoder
)(
nil
)
var
_
CodeGenerator
=
(
*
encoder
)(
nil
)
var
_
CodeGenerator
=
(
*
decoder
)(
nil
)
var
_
CodeGenerator
=
(
*
decoder
)(
nil
)
func
(
s
*
size
r
)
generatedCode
()
string
{
func
(
s
*
size
CodeGen
)
generatedCode
()
string
{
code
:=
Buffer
{}
code
:=
Buffer
{}
// prologue
// prologue
code
.
emit
(
"func (%s *%s) NEOEncodedLen() int {"
,
s
.
recvName
,
s
.
typeName
)
code
.
emit
(
"func (%s *%s) NEOEncodedLen() int {"
,
s
.
recvName
,
s
.
typeName
)
...
@@ -396,9 +403,7 @@ func (s *sizer) generatedCode() string {
...
@@ -396,9 +403,7 @@ func (s *sizer) generatedCode() string {
func
(
e
*
encoder
)
generatedCode
()
string
{
func
(
e
*
encoder
)
generatedCode
()
string
{
code
:=
Buffer
{}
code
:=
Buffer
{}
// prologue
// prologue
if
e
.
recvName
!=
""
{
code
.
emit
(
"func (%s *%s) NEOEncode(data []byte) {"
,
e
.
recvName
,
e
.
typeName
)
code
.
emit
(
"func (%s *%s) NEOEncode(data []byte) {"
,
e
.
recvName
,
e
.
typeName
)
}
code
.
Write
(
e
.
Bytes
())
// XXX -> e.buf.Bytes() ?
code
.
Write
(
e
.
Bytes
())
// XXX -> e.buf.Bytes() ?
...
@@ -415,7 +420,6 @@ func (d *decoder) emit(format string, a ...interface{}) {
...
@@ -415,7 +420,6 @@ func (d *decoder) emit(format string, a ...interface{}) {
// XXX place?
// XXX place?
// data <- data[pos:]
// data <- data[pos:]
// add overflow checkpoint XXX
// pos <- 0
// pos <- 0
func
(
d
*
decoder
)
resetPos
()
{
func
(
d
*
decoder
)
resetPos
()
{
if
d
.
n
!=
0
{
if
d
.
n
!=
0
{
...
@@ -430,19 +434,24 @@ func (d *decoder) resetPos() {
...
@@ -430,19 +434,24 @@ func (d *decoder) resetPos() {
// mark current place for delayed insertion of overflow check code
// mark current place for delayed insertion of overflow check code
//
//
// delayed: because we go forward in decode path scanning ahead as far as we
// delayed: because we go forward in decode path scanning ahead as far as we
// can - until first variable-size encoded something, and then insert checking
// can - until first variable-size encoded something, and then - knowing fixed
// condition for accumulated size to here-marked overflow checkpoint.
// size would be read - insert checking condition for accumulated size to
// here-marked overflow checkpoint.
//
//
// so overflowCheckpoint does:
// so overflowCheckpoint does:
// 1. emit overflow checking code for previous overflow checkpoint
// 1. emit overflow checking code for previous overflow checkpoint
// 2. mark current place as next overflow checkpoint to eventually emit
// 2. mark current place as next overflow checkpoint to eventually emit
//
// it is inserted
// - before reading variable sized item
// - XXX in loops ?
func
(
d
*
decoder
)
overflowCheckpoint
()
{
func
(
d
*
decoder
)
overflowCheckpoint
()
{
//d.buf.emit("// overflow check point")
//d.buf.emit("// overflow check point")
if
!
d
.
overflowCheckSize
.
IsZero
()
{
if
!
d
.
overflowCheckSize
.
IsZero
()
{
d
.
buf
.
emit
(
"if uint32(len(data)) < %v { goto overflow }"
,
&
d
.
overflowCheckSize
)
d
.
buf
.
emit
(
"if uint32(len(data)) < %v { goto overflow }"
,
&
d
.
overflowCheckSize
)
}
}
d
.
overflowCheckSize
=
SymSize
{}
// zero
d
.
overflowCheckSize
.
Reset
()
d
.
buf
.
Write
(
d
.
bufCur
.
Bytes
())
d
.
buf
.
Write
(
d
.
bufCur
.
Bytes
())
d
.
bufCur
.
Reset
()
d
.
bufCur
.
Reset
()
...
@@ -453,9 +462,7 @@ func (d *decoder) generatedCode() string {
...
@@ -453,9 +462,7 @@ func (d *decoder) generatedCode() string {
code
:=
Buffer
{}
code
:=
Buffer
{}
// prologue
// prologue
if
d
.
recvName
!=
""
{
code
.
emit
(
"func (%s *%s) NEODecode(data []byte) (int, error) {"
,
d
.
recvName
,
d
.
typeName
)
code
.
emit
(
"func (%s *%s) NEODecode(data []byte) (int, error) {"
,
d
.
recvName
,
d
.
typeName
)
}
if
d
.
varUsed
[
"nread"
]
{
if
d
.
varUsed
[
"nread"
]
{
code
.
emit
(
"var %v uint32"
,
d
.
var_
(
"nread"
))
code
.
emit
(
"var %v uint32"
,
d
.
var_
(
"nread"
))
}
}
...
@@ -479,8 +486,8 @@ func (d *decoder) generatedCode() string {
...
@@ -479,8 +486,8 @@ func (d *decoder) generatedCode() string {
return
code
.
String
()
return
code
.
String
()
}
}
// emit code to size/encode/decode basic fixed type
func
(
s
*
size
r
)
genBasic
(
path
string
,
typ
*
types
.
Basic
,
userType
types
.
Type
)
{
func
(
s
*
size
CodeGen
)
genBasic
(
path
string
,
typ
*
types
.
Basic
,
userType
types
.
Type
)
{
basic
:=
basicTypes
[
typ
.
Kind
()]
basic
:=
basicTypes
[
typ
.
Kind
()]
s
.
size
.
Add
(
basic
.
wireSize
)
s
.
size
.
Add
(
basic
.
wireSize
)
}
}
...
@@ -500,7 +507,6 @@ func (e *encoder) genBasic(path string, typ *types.Basic, userType types.Type) {
...
@@ -500,7 +507,6 @@ func (e *encoder) genBasic(path string, typ *types.Basic, userType types.Type) {
func
(
d
*
decoder
)
genBasic
(
assignto
string
,
typ
*
types
.
Basic
,
userType
types
.
Type
)
{
func
(
d
*
decoder
)
genBasic
(
assignto
string
,
typ
*
types
.
Basic
,
userType
types
.
Type
)
{
basic
:=
basicTypes
[
typ
.
Kind
()]
basic
:=
basicTypes
[
typ
.
Kind
()]
//d.emit("if len(data) < %v { goto overflow }", d.n + basic.wireSize)
dataptr
:=
fmt
.
Sprintf
(
"data[%v:]"
,
d
.
n
)
dataptr
:=
fmt
.
Sprintf
(
"data[%v:]"
,
d
.
n
)
decoded
:=
fmt
.
Sprintf
(
basic
.
decode
,
dataptr
)
decoded
:=
fmt
.
Sprintf
(
basic
.
decode
,
dataptr
)
d
.
n
+=
basic
.
wireSize
d
.
n
+=
basic
.
wireSize
...
@@ -518,10 +524,10 @@ func (d *decoder) genBasic(assignto string, typ *types.Basic, userType types.Typ
...
@@ -518,10 +524,10 @@ func (d *decoder) genBasic(assignto string, typ *types.Basic, userType types.Typ
d
.
emit
(
"%s= %s"
,
assignto
,
decoded
)
d
.
emit
(
"%s= %s"
,
assignto
,
decoded
)
}
}
// emit code to encode/decode string or []byte
// emit code to
size/
encode/decode string or []byte
// len u32
// len u32
// [len]byte
// [len]byte
func
(
s
*
size
r
)
genSlice1
(
path
string
,
typ
types
.
Type
)
{
func
(
s
*
size
CodeGen
)
genSlice1
(
path
string
,
typ
types
.
Type
)
{
s
.
size
.
Add
(
4
)
s
.
size
.
Add
(
4
)
s
.
size
.
AddExpr
(
"len(%s)"
,
path
)
s
.
size
.
AddExpr
(
"len(%s)"
,
path
)
}
}
...
@@ -568,8 +574,9 @@ func (d *decoder) genSlice1(assignto string, typ types.Type) {
...
@@ -568,8 +574,9 @@ func (d *decoder) genSlice1(assignto string, typ types.Type) {
d
.
emit
(
"}"
)
d
.
emit
(
"}"
)
}
}
// array with sizeof(elem)==1
// emit code to size/encode/decode array with sizeof(elem)==1
func
(
s
*
sizer
)
genArray1
(
path
string
,
typ
*
types
.
Array
)
{
// [len(A)]byte
func
(
s
*
sizeCodeGen
)
genArray1
(
path
string
,
typ
*
types
.
Array
)
{
s
.
size
.
Add
(
int
(
typ
.
Len
()))
s
.
size
.
Add
(
int
(
typ
.
Len
()))
}
}
...
@@ -588,21 +595,21 @@ func (d *decoder) genArray1(assignto string, typ *types.Array) {
...
@@ -588,21 +595,21 @@ func (d *decoder) genArray1(assignto string, typ *types.Array) {
}
}
// emit code to encode/decode slice
// emit code to
size/
encode/decode slice
// len u32
// len u32
// [len]item
// [len]item
func
(
s
*
sizer
)
genSlice
(
path
string
,
typ
*
types
.
Slice
,
obj
types
.
Object
)
{
func
(
s
*
sizeCodeGen
)
genSlice
(
path
string
,
typ
*
types
.
Slice
,
obj
types
.
Object
)
{
s
.
size
.
Add
(
4
)
// if size(item)==const - size update in one go
// if size(item)==const - size update in one go
elemSize
,
ok
:=
typeSizeFixed
(
typ
.
Elem
())
elemSize
,
ok
:=
typeSizeFixed
(
typ
.
Elem
())
if
ok
{
if
ok
{
s
.
size
.
Add
(
4
)
s
.
size
.
AddExpr
(
"len(%v) * %v"
,
path
,
elemSize
)
s
.
size
.
AddExpr
(
"len(%v) * %v"
,
path
,
elemSize
)
return
return
}
}
s
.
size
.
Add
(
4
)
curSize
:=
s
.
size
curSize
:=
s
.
size
s
.
size
=
SymSize
{}
// zero
s
.
size
.
Reset
()
s
.
emit
(
"for i := 0; i < len(%v); i++ {"
,
path
)
s
.
emit
(
"for i := 0; i < len(%v); i++ {"
,
path
)
s
.
emit
(
"a := &%s[i]"
,
path
)
s
.
emit
(
"a := &%s[i]"
,
path
)
...
@@ -618,7 +625,6 @@ func (s *sizer) genSlice(path string, typ *types.Slice, obj types.Object) {
...
@@ -618,7 +625,6 @@ func (s *sizer) genSlice(path string, typ *types.Slice, obj types.Object) {
s
.
size
=
curSize
s
.
size
=
curSize
}
}
// TODO optimize for []byte
func
(
e
*
encoder
)
genSlice
(
path
string
,
typ
*
types
.
Slice
,
obj
types
.
Object
)
{
func
(
e
*
encoder
)
genSlice
(
path
string
,
typ
*
types
.
Slice
,
obj
types
.
Object
)
{
e
.
emit
(
"{"
)
e
.
emit
(
"{"
)
e
.
emit
(
"l := uint32(len(%s))"
,
path
)
e
.
emit
(
"l := uint32(len(%s))"
,
path
)
...
@@ -630,12 +636,10 @@ func (e *encoder) genSlice(path string, typ *types.Slice, obj types.Object) {
...
@@ -630,12 +636,10 @@ func (e *encoder) genSlice(path string, typ *types.Slice, obj types.Object) {
codegenType
(
"(*a)"
,
typ
.
Elem
(),
obj
,
e
)
codegenType
(
"(*a)"
,
typ
.
Elem
(),
obj
,
e
)
e
.
emit
(
"data = data[%v:]"
,
e
.
n
)
// FIXME wrt slice of slice ?
e
.
emit
(
"data = data[%v:]"
,
e
.
n
)
// FIXME wrt slice of slice ?
e
.
emit
(
"}"
)
e
.
emit
(
"}"
)
// see vvv
e
.
emit
(
"}"
)
e
.
emit
(
"}"
)
e
.
n
=
0
e
.
n
=
0
}
}
// TODO optimize for []byte
func
(
d
*
decoder
)
genSlice
(
assignto
string
,
typ
*
types
.
Slice
,
obj
types
.
Object
)
{
func
(
d
*
decoder
)
genSlice
(
assignto
string
,
typ
*
types
.
Slice
,
obj
types
.
Object
)
{
d
.
emit
(
"{"
)
d
.
emit
(
"{"
)
d
.
genBasic
(
"l:"
,
types
.
Typ
[
types
.
Uint32
],
nil
)
d
.
genBasic
(
"l:"
,
types
.
Typ
[
types
.
Uint32
],
nil
)
...
@@ -675,15 +679,13 @@ func (d *decoder) genSlice(assignto string, typ *types.Slice, obj types.Object)
...
@@ -675,15 +679,13 @@ func (d *decoder) genSlice(assignto string, typ *types.Slice, obj types.Object)
d
.
emit
(
"}"
)
d
.
emit
(
"}"
)
d
.
overflowChecked
=
overflowCheckedCur
d
.
overflowChecked
=
overflowCheckedCur
//d.emit("%v= string(data[:l])", assignto)
d
.
emit
(
"}"
)
d
.
emit
(
"}"
)
}
}
// generate code to encode/decode map
// generate code to encode/decode map
// len u32
// len u32
// [len](key, value)
// [len](key, value)
func
(
s
*
size
r
)
genMap
(
path
string
,
typ
*
types
.
Map
,
obj
types
.
Object
)
{
func
(
s
*
size
CodeGen
)
genMap
(
path
string
,
typ
*
types
.
Map
,
obj
types
.
Object
)
{
keySize
,
keyFixed
:=
typeSizeFixed
(
typ
.
Key
())
keySize
,
keyFixed
:=
typeSizeFixed
(
typ
.
Key
())
elemSize
,
elemFixed
:=
typeSizeFixed
(
typ
.
Elem
())
elemSize
,
elemFixed
:=
typeSizeFixed
(
typ
.
Elem
())
...
@@ -695,7 +697,7 @@ func (s *sizer) genMap(path string, typ *types.Map, obj types.Object) {
...
@@ -695,7 +697,7 @@ func (s *sizer) genMap(path string, typ *types.Map, obj types.Object) {
s
.
size
.
Add
(
4
)
s
.
size
.
Add
(
4
)
curSize
:=
s
.
size
curSize
:=
s
.
size
s
.
size
=
SymSize
{}
// zero
s
.
size
.
Reset
()
// FIXME for map of map gives ...[key][key] => key -> different variables
// FIXME for map of map gives ...[key][key] => key -> different variables
s
.
emit
(
"for key := range %s {"
,
path
)
s
.
emit
(
"for key := range %s {"
,
path
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment