Merge "Endian swap the message size parameter."
diff --git a/api/ast/api.go b/api/ast/api.go
new file mode 100644
index 0000000..6135ea8
--- /dev/null
+++ b/api/ast/api.go
@@ -0,0 +1,48 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// package ast holds the set of types used in the abstract syntax tree
+// representation of the api language.
+package ast
+
+import "android.googlesource.com/platform/tools/gpu/parse"
+
+// API is the root of the AST tree, and constitutes one entire parsed file.
+// It holds the set of top level AST nodes, grouped by type.
+type API struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Macros []*Function // functions declared with the "macro" keyword
+ Externs []*Function // functions declared with the "extern" keyword
+ Commands []*Function // functions declared with the "cmd" keyword
+ Pseudonyms []*Pseudonym // strong type aliases declared with the "type" keyword
+ Aliases []*Alias // weak type aliases declared with the "alias" keyword
+ Enums []*Enum // enumerated types, declared with the "enum" keyword
+ Classes []*Class // class types, declared with the "class" keyword
+ Fields []*Field // variables declared at the global scope
+}
+
+// Annotation is the AST node that represents «@name(arguments) constructs»
+type Annotation struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Name *Identifier // the name part (between the @ and the brackets)
+ Arguments []interface{} // the list of arguments (the bit in brackets)
+}
+
+// Annotations represents the set of Annotation objects that apply to another
+// AST node.
+type Annotations []*Annotation
+
+// Invalid is used when an error was encountered in the parsing, but we want to
+// keep going. If there are no errors, this will never be in the tree.
+type Invalid struct{}
diff --git a/api/ast/expression.go b/api/ast/expression.go
new file mode 100644
index 0000000..400d451
--- /dev/null
+++ b/api/ast/expression.go
@@ -0,0 +1,97 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "android.googlesource.com/platform/tools/gpu/parse"
+
+// Block represents a linear sequence of statements, most often the contents
+// of a {} pair.
+type Block struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Docs *URL // the url to the documentation for this block
+ Statements []interface{} // The set of statements that make up the block
+}
+
+// If represents an «"if" condition { trueblock } "else" { falseblock }» structure.
+type If struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Condition interface{} // the condition to use to select which block is active
+ True *Block // the block to use if condition is true
+ False *Block // the block to use if condition is false
+}
+
+// Iteration represents a «"for" variable "in" iterable { block }» structure.
+type Iteration struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Variable *Identifier // the variable to use for the iteration value
+ Iterable interface{} // the expression that produces the iterable to loop over
+ Block *Block // the block to run once per item in the iterable
+}
+
+// Switch represents a «"switch" value { cases }» structure.
+// The first matching case is selected.
+// If a switch is used as an expression, the case blocks must all be a single
+// expression.
+type Switch struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Value interface{} // the value to match against
+ Cases []*Case // the set of cases to match the value with
+}
+
+// Case represents a «"case" conditions: block» structure within a switch statement.
+// The conditions are a comma separated list of expressions the switch statement
+// value will be compared against.
+type Case struct {
+ CST *parse.Branch // underlying parse structure for this node.
+ Conditions []interface{} // the set of conditions that would select this case
+ Block *Block // the block to run if this case is selected
+}
+
+// Group represents the «(expression)» construct, a single parenthesized expression.
+type Group struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Expression interface{} // the expression within the parentheses
+}
+
+// DeclareLocal represents a «name := value» statement that declares a new
+// immutable local variable with the specified value and inferred type.
+type DeclareLocal struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Name *Identifier // the name to give the new local
+ RHS interface{} // the value to store in that local
+}
+
+// Assign represents a «location = value» statement that assigns a value to an
+// existing mutable location.
+type Assign struct {
+ CST *parse.Branch // underlying parse structure for this node
+ LHS interface{} // the location to store the value into
+ RHS interface{} // the value to store
+}
+
+// Assert represents the «"assert" condition» statement.
+// Used mostly to express the pre-conditions of api commands, such as acceptable
+// values for parameters that cannot be expressed in the type system.
+type Assert struct {
+ CST *parse.Branch // underlying parse structure for this node.
+ Condition interface{} // the condition to check, should be true
+}
+
+// Length represents the «"len"(value)» construct, were value should be an
+// expresssion that returns an object of array, string or map type.
+type Length struct {
+ CST *parse.Branch // underlying parse structure for this node.
+ Object interface{} // the object to query the length of
+}
diff --git a/api/ast/function.go b/api/ast/function.go
new file mode 100644
index 0000000..48352ef
--- /dev/null
+++ b/api/ast/function.go
@@ -0,0 +1,49 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "android.googlesource.com/platform/tools/gpu/parse"
+
+// Function represents the declaration of a callable entity, any of "cmd", "extern" or "macro".
+// Its structure is «return_type name(parameters) body»
+// where parameters is a comma separated list and body is an optional block.
+type Function struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Annotations Annotations // the annotations applied to this function
+ Name *Identifier // the name of the function
+ Parameters []*Parameter // the parameters the function takes
+ Block *Block // the body of the function if present
+}
+
+// Parameter represents a single parameter in the set of parameters for a Function.
+// It has the structure «["in"|"out"|"inout"|"this"] type name»
+type Parameter struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Annotations Annotations // the annotations applied to this parameter
+ Input bool // true if the parameter is an input
+ Output bool // true if the parameters is an output
+ This bool // true if the parameter is the this pointer of a method
+ Type interface{} // the type of the parameter
+ Name *Identifier // the name the parameter as exposed to the body
+}
+
+// Call is an expression that invokes a function with a set of arguments.
+// It has the structure «target(arguments)» where target must be a function and
+// arguments is a comma separated list of expressions.
+type Call struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Target interface{} // the function to invoke
+ Arguments []interface{} // the arguments to the function
+}
diff --git a/api/ast/identifier.go b/api/ast/identifier.go
new file mode 100644
index 0000000..94e861d
--- /dev/null
+++ b/api/ast/identifier.go
@@ -0,0 +1,56 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "android.googlesource.com/platform/tools/gpu/parse"
+
+// Identifier holds a parsed identifier in the parse tree.
+type Identifier struct {
+ CST *parse.Leaf // underlying parse leaf for this node
+ Value string // the identifier
+}
+
+const (
+ // Keyword strings represent places in the syntax where a word has special
+ // meaning.
+ KeywordAPI = "api"
+ KeywordAlias = "alias"
+ KeywordArray = "array"
+ KeywordAs = "as"
+ KeywordAssert = "assert"
+ KeywordBitfield = "bitfield"
+ KeywordCase = "case"
+ KeywordClass = "class"
+ KeywordCmd = "cmd"
+ KeywordElse = "else"
+ KeywordEnum = "enum"
+ KeywordExtern = "extern"
+ KeywordFalse = "false"
+ KeywordFor = "for"
+ KeywordIf = "if"
+ KeywordIn = "in"
+ KeywordInout = "inout"
+ KeywordLength = "len"
+ KeywordMacro = "macro"
+ KeywordMap = "map"
+ KeywordNew = "new"
+ KeywordOut = "out"
+ KeywordPseudonym = "type"
+ KeywordPtr = "ptr"
+ KeywordSwitch = "switch"
+ KeywordThis = "this"
+ KeywordTrue = "true"
+ KeywordWhen = "when"
+)
diff --git a/api/ast/literal.go b/api/ast/literal.go
new file mode 100644
index 0000000..fb68994
--- /dev/null
+++ b/api/ast/literal.go
@@ -0,0 +1,51 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import (
+ "net/url"
+
+ "android.googlesource.com/platform/tools/gpu/parse"
+)
+
+// Number represents a typeless numeric constant.
+type Number struct {
+ CST *parse.Leaf // underlying parse leaf for this node
+ Value string // the string representation of the constant
+}
+
+// Bool is used for the "true" and "false" keywords.
+type Bool struct {
+ CST *parse.Leaf // underlying parse leaf for this node
+ Value bool // The value of the boolean
+}
+
+// String represents a quoted string constant.
+type String struct {
+ CST *parse.Leaf // underlying parse leaf for this node
+ Value string // The body of the string, not including the delimiters
+}
+
+// Unknown represents the "?" construct. This is used in places where an
+// expression takes a value that is implementation defined.
+type Unknown struct {
+ CST *parse.Leaf // underlying parse leaf for this node
+}
+
+// URL holds things that start with "http:", used for documentation links in blocks.
+type URL struct {
+ CST *parse.Leaf // underlying parse leaf for this node
+ URL url.URL // the actual url
+}
diff --git a/api/ast/operator.go b/api/ast/operator.go
new file mode 100644
index 0000000..680cb22
--- /dev/null
+++ b/api/ast/operator.go
@@ -0,0 +1,141 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import (
+ "sort"
+
+ "android.googlesource.com/platform/tools/gpu/parse"
+)
+
+const (
+ // Runes with special meaning to the parser.
+ Quote = '"'
+)
+
+const (
+ // The set of operators understood by the parser.
+ OpUnknown = "?"
+ OpBlockStart = "{"
+ OpBlockEnd = "}"
+ OpIndexStart = "["
+ OpIndexEnd = "]"
+ OpListStart = "("
+ OpListSeparator = ","
+ OpListEnd = ")"
+ OpMetaStart = "<"
+ OpMetaEnd = ">"
+ OpEndStatement = ";"
+ OpAssign = "="
+ OpDeclare = ":="
+ OpMember = "."
+ OpExtends = ":"
+ OpAnnotation = "@"
+ OpInitialise = ":"
+ OpPointer = "*"
+ OpEQ = "=="
+ OpGT = ">"
+ OpLT = "<"
+ OpGE = ">="
+ OpLE = "<="
+ OpNE = "!="
+ OpOr = "||"
+ OpAnd = "&&"
+ OpPlus = "+"
+ OpMinus = "-"
+ OpMultiply = "*"
+ OpDivide = "/"
+ OpRange = ".."
+ OpNot = "!"
+ OpIn = "in"
+)
+
+var (
+ Operators = []string{} // all valid operator strings, sorted in descending length order
+ UnaryOperators = map[string]struct{}{} // the map of valid unary operators
+ BinaryOperators = map[string]struct{}{} // the map of valid boolean operators
+)
+
+// UnaryOp represents any unary operation applied to an expression.
+type UnaryOp struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Operator string // the operator being applied
+ Expression interface{} // the expression the operator is being applied to
+}
+
+// BinaryOp represents any binary operation applied to two expressions.
+type BinaryOp struct {
+ CST *parse.Branch // underlying parse structure for this node
+ LHS interface{} // the expression on the left of the operator
+ Operator string // the operator being applied
+ RHS interface{} // the expression on the right of the operator
+}
+
+func init() {
+ for _, op := range []string{
+ OpUnknown,
+ OpBlockStart,
+ OpBlockEnd,
+ OpIndexStart,
+ OpIndexEnd,
+ OpListStart,
+ OpListSeparator,
+ OpListEnd,
+ OpMetaStart,
+ OpMetaEnd,
+ OpEndStatement,
+ OpAssign,
+ OpDeclare,
+ OpMember,
+ OpExtends,
+ OpAnnotation,
+ OpInitialise,
+ OpPointer,
+ } {
+ Operators = append(Operators, op)
+ }
+ for _, op := range []string{
+ OpEQ,
+ OpGT,
+ OpLT,
+ OpGE,
+ OpLE,
+ OpNE,
+ OpOr,
+ OpAnd,
+ OpPlus,
+ OpMinus,
+ OpMultiply,
+ OpDivide,
+ OpRange,
+ OpIn,
+ } {
+ Operators = append(Operators, op)
+ BinaryOperators[op] = struct{}{}
+ }
+ for _, op := range []string{
+ OpNot,
+ } {
+ Operators = append(Operators, op)
+ UnaryOperators[op] = struct{}{}
+ }
+ sort.Sort(opsByLength(Operators))
+}
+
+type opsByLength []string
+
+func (a opsByLength) Len() int { return len(a) }
+func (a opsByLength) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a opsByLength) Less(i, j int) bool { return len(a[i]) > len(a[j]) }
diff --git a/api/ast/type.go b/api/ast/type.go
new file mode 100644
index 0000000..56370c6
--- /dev/null
+++ b/api/ast/type.go
@@ -0,0 +1,153 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package ast
+
+import "android.googlesource.com/platform/tools/gpu/parse"
+
+// Class represents a class type declaration of the form
+// «"class" name : extension_list { fields }»
+type Class struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Annotations Annotations // the annotations applied to the class
+ Name *Identifier // the name of the class
+ Extends []*Identifier // the set of class names it extends
+ Fields []*Field // the fields of the class
+}
+
+// ClassInitializer represents a class literal declaration, of the form
+// «name { field_initializers }»
+type ClassInitializer struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Class *Identifier // the name of the class instantiate
+ Fields []*FieldInitializer // the initializers for the class fields
+}
+
+// New represents an expression that allocates a new class instance and returns
+// a pointer to it. It takes a class initializer to specify both the type and
+// the initial value for the instance.
+type New struct {
+ CST *parse.Branch // underlying parse structure for this node
+ ClassInitializer *ClassInitializer
+}
+
+// Field represents a field of a class or api, with the structure
+// «type name = expression»
+type Field struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Annotations Annotations // the annotations applied to the field
+ Type interface{} // the type the field holds
+ Name *Identifier // the name of the field
+ Default interface{} // the default value expression for the field
+}
+
+// FieldInitializer is used as part of a ClassInitializer to specify the value a
+// single field should have.
+type FieldInitializer struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Name *Identifier // the name of the field
+ Value interface{} // the value the field should be given
+}
+
+// As represents a type coercion expression, of the form «expression "as" type»
+type As struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Object interface{} // the value to force the type of
+ Type interface{} // the type it should be coerced to
+}
+
+// EnumEntry represents a single value in an enumerated type.
+type EnumEntry struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Owner *Enum // the enum this entry is a part of
+ Name *Identifier // the name this entry is given
+ Value *Number // the value of this entry
+}
+
+// Enum represents an enumerated type declaration, of the form
+// «"enum" name { entries }» where entries is a comma separated list of «name = value»
+type Enum struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Annotations Annotations // the annotations applied to the enum
+ Name *Identifier // the name of the enum
+ IsBitfield bool // whether this enum represents a bitfield form
+ Entries []*EnumEntry // the set of valid entries for this enum
+ Extends []*Identifier // deprecated list of enums this extends
+}
+
+// Member represents an expressions that access members of objects.
+// Always of the form «object.name» where object is an expression.
+type Member struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Object interface{} // the object to get a member of
+ Name *Identifier // the name of the member to get
+}
+
+// Index represents any expression of the form «object[index]»
+// Used for arrays, maps and bitfields.
+type Index struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Object interface{} // the object to index
+ Index interface{} // the index to lookup
+}
+
+// ArrayType represents a type declaration for an array, which looks
+// like «"array"<value_type>»
+type ArrayType struct {
+ CST *parse.Branch // underlying parse structure for this node
+ ValueType interface{} // the type stored as elements of the array
+}
+
+// StaticArrayType represents a type declaration for a constant size array,
+// which looks like «type[dimensions]»
+// dimensions is a comma separated list of dimensions, for declaring
+// multidimensional arrays, for instance f32[4,4] for a matrix.
+type StaticArrayType struct {
+ CST *parse.Branch // underlying parse structure for this node
+ ValueType interface{} // The type to store in the array
+ Dimensions []interface{} // the dimensions of the array
+}
+
+// MapType represents a type declaration of a map, of the form
+// «map<key_type, value_type>»
+type MapType struct {
+ CST *parse.Branch // underlying parse structure for this node
+ KeyType interface{} // the type used to index the map
+ ValueType interface{} // the type stored against the index in the map
+}
+
+// PointerType represents a pointer type declaration, of the form «type*»
+type PointerType struct {
+ CST *parse.Branch // underlying parse structure for this node
+ To interface{} // the underlying type this pointer points to
+}
+
+// Alias represents a weak type alias, with structure «"alias" type name».
+// An alias does not declare a new type, just a reusable name for a common type.
+type Alias struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Annotations Annotations // the annotations applied to the alias
+ Name *Identifier // the name of the alias
+ To interface{} // the type it is an alias for
+}
+
+// Pseudonym declares a new type in terms of another type.
+// Has the form «"type" type name»
+// Pseydonyms are proper types, but the underlying type can be discovered.
+type Pseudonym struct {
+ CST *parse.Branch // underlying parse structure for this node
+ Annotations Annotations // the annotations applied to the type
+ Name *Identifier // the name of the type
+ To interface{} // the underlying type
+}
diff --git a/binary/codergen/main.go b/binary/codergen/main.go
new file mode 100644
index 0000000..17132a3
--- /dev/null
+++ b/binary/codergen/main.go
@@ -0,0 +1,100 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Codergen is a tool to parse go code and automatically generate encoders and
+// decoders for the structs it finds.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "android.googlesource.com/platform/tools/gpu/binary/generate"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+)
+
+var (
+ golang = flag.String("go", "", "the go file to generate")
+ java = flag.String("java", "", "the java file to generate")
+)
+
+func run() error {
+ flag.Parse()
+ config := loader.Config{SourceImports: true}
+ _, err := config.FromArgs(flag.Args(), false)
+ if err != nil {
+ return err
+ }
+ config.AllowErrors = true
+ info, err := config.Load()
+ if err != nil {
+ return err
+ }
+ file := generate.File{}
+ for _, pkg := range info.Created {
+ file.Package = pkg.Pkg.Name()
+ for _, def := range pkg.Defs {
+ if n, ok := def.(*types.TypeName); ok {
+ if t, ok := n.Type().(*types.Named); ok {
+ if _, ok := t.Underlying().(*types.Struct); ok {
+ file.Structs = append(file.Structs, generate.FromTypename(pkg.Pkg, n))
+ }
+ }
+ }
+ }
+ }
+ generate.Sort(file.Structs)
+ if *golang != "" {
+ file := file
+ file.Generated = fmt.Sprintf("codergen -go=%s", *golang)
+ result, err := generate.GoFile(&file)
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(*golang, result, os.ModePerm)
+ if err != nil {
+ return err
+ }
+ }
+ if *java != "" {
+ file := file
+ file.Generated = fmt.Sprintf("codergen -java=%s", filepath.Base(*java))
+ // pick off the package part
+ smashed := strings.Split(*java, "/com/")
+ file.Package = "com." + strings.Replace(smashed[len(smashed)-1], "/", ".", -1)
+ filename := filepath.Join(*java, "ObjectFactory.java")
+ result, err := generate.JavaFile(&file)
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(filename, result, os.ModePerm)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func main() {
+ if err := run(); err != nil {
+ fmt.Fprintf(os.Stderr, "codergen failed: %v\n", err)
+ os.Exit(1)
+ }
+}
diff --git a/binary/decoder.go b/binary/decoder.go
index c548600..a620e4a 100644
--- a/binary/decoder.go
+++ b/binary/decoder.go
@@ -15,10 +15,8 @@
package binary
import (
- "fmt"
"io"
"math"
- "reflect"
)
// Decoder provides methods for decoding values to an io.Reader.
@@ -167,12 +165,6 @@
return buf, err
}
-type unknownTypeID TypeID
-
-func (e unknownTypeID) Error() string {
- return fmt.Sprintf("Unknown type id %x encountered in binary.Decoder", TypeID(e))
-}
-
// Object decodes and returns an Object from the Decoder's io.Reader. Object instances that were
// encoded multiple times will be decoded and returned as a shared, single instance.
// The type id in the stream must have been previously registered with binary.Register.
@@ -194,11 +186,12 @@
if err != nil {
return nil, err
}
- t, idFound := idToType[id]
- if !idFound {
- return nil, unknownTypeID(id)
+
+ obj, err := MakeObject(id)
+ if err != nil {
+ return nil, err
}
- obj := reflect.New(t).Interface().(Decodable)
+
if err = obj.Decode(d); err != nil {
return nil, err
}
diff --git a/binary/encoder.go b/binary/encoder.go
index c36af06..c38875c 100644
--- a/binary/encoder.go
+++ b/binary/encoder.go
@@ -15,10 +15,8 @@
package binary
import (
- "fmt"
"io"
"math"
- "reflect"
)
// Encoder provides methods for encoding values to an io.Writer.
@@ -153,14 +151,6 @@
return e.write(data)
}
-type unknownType struct {
- Object Encodable
-}
-
-func (e unknownType) Error() string {
- return fmt.Sprintf("Unknown type %T encountered in binary.Encoder", e.Object)
-}
-
// Object encodes an Encodable to the Encoder's io.Writer. If Object is called repeatedly with the
// same argument (i.e. the argument has identical dynamic types and equal dynamic values), then the
// argument will only be encoded with the first call, and later encodings will reference the first
@@ -176,9 +166,9 @@
return e.Uint16(key)
}
- id, idFound := typeToID[reflect.TypeOf(obj)]
- if !idFound {
- return unknownType{obj}
+ id, err := TypeOf(obj)
+ if err != nil {
+ return err
}
key = uint16(len(e.objects))
diff --git a/binary/float16.go b/binary/float16.go
index fc1a9e8..6c342ed 100644
--- a/binary/float16.go
+++ b/binary/float16.go
@@ -17,19 +17,29 @@
import "unsafe"
// Float16 represents a 16-bit floating point number, containing a single sign bit, 5 exponent bits
-// and 10 fractional bits:
+// and 10 fractional bits. This corresponds to IEEE 754-2008 binary16 (or half precision float) type.
//
// MSB LSB
// ╔════╦════╤════╤════╤════╤════╦════╤════╤════╤════╤════╤════╤════╤════╤════╤════╗
// ║Sign║ E₄ │ E₃ │ E₂ │ E₁ │ E₀ ║ F₉ │ F₈ │ F₇ │ F₆ │ F₅ │ F₄ │ F₃ │ F₂ │ F₁ │ F₀ ║
// ╚════╩════╧════╧════╧════╧════╩════╧════╧════╧════╧════╧════╧════╧════╧════╧════╝
// Where E is the exponent bits and F is the fractional bits.
-//
-// This floating-point number is similar to IEEE 754-2008, but Float16 does not support NaNs nor
-// ±Infs.
type Float16 uint16
-// Float32 returns the Float16 value expanded to a float32
+const (
+ float16ExpMask Float16 = 0x7c00
+ float16ExpBias uint32 = 0xf
+ float16ExpShift uint32 = 10
+ float16FracMask Float16 = 0x03ff
+ float16SignMask Float16 = 0x8000
+ float32ExpMask uint32 = 0x7f800000
+ float32ExpBias uint32 = 0x7f
+ float32ExpShift uint32 = 23
+ float32FracMask uint32 = 0x007fffff
+)
+
+// Float32 returns the Float16 value expanded to a float32. Infinities and NaNs are expanded as
+// such.
func (f Float16) Float32() float32 {
u32 := expandF16ToF32(f)
ptr := unsafe.Pointer(&u32)
@@ -37,16 +47,93 @@
return f32
}
-func expandF16ToF32(in Float16) uint32 {
- sign := uint32(in&0x8000) << 16
- nonSign := uint32(in&0x7fff) << 13
- exp := uint32(in & 0x7c00)
+// IsNaN reports whether f is an “not-a-number” value.
+func (f Float16) IsNaN() bool { return (f&float16ExpMask == float16ExpMask) && (f&float16FracMask != 0) }
- nonSign += 0x38000000
+// IsInf reports whether f is an infinity, according to sign. If sign > 0, IsInf reports whether
+// f is positive infinity. If sign < 0, IsInf reports whether f is negative infinity. If sign ==
+// 0, IsInf reports whether f is either infinity.
+func (f Float16) IsInf(sign int) bool {
+ return ((f == float16ExpMask) && sign >= 0) ||
+ (f == (float16SignMask|float16ExpMask) && sign <= 0)
+}
- if exp == 0 {
- nonSign = 0
+// Float16NaN returns an “not-a-number” value.
+func NewFloat16NaN() Float16 { return float16ExpMask | float16FracMask }
+
+// Float16Inf returns positive infinity if sign >= 0, negative infinity if sign < 0.
+func NewFloat16Inf(sign int) Float16 {
+ if sign >= 0 {
+ return float16ExpMask
+ } else {
+ return float16SignMask | float16ExpMask
+ }
+}
+
+// NewFloat16 returns a Float16 encoding of a 32-bit floating point number. Infinities and NaNs
+// are encoded as such. Very large and very small numbers get rounded to infinity and zero
+// respectively.
+func NewFloat16(f32 float32) Float16 {
+ ptr := unsafe.Pointer(&f32)
+ u32 := *(*uint32)(ptr)
+
+ sign := Float16(u32>>16) & float16SignMask
+ exp := (u32 & float32ExpMask) >> float32ExpShift
+ frac := u32 & 0x7fffff
+
+ if exp == 0xff {
+ // NaN or Infinity
+ if frac != 0 { // NaN
+ frac = 0x3f
+ }
+
+ return sign | float16ExpMask | Float16(frac)
}
- return sign | nonSign
+ if exp+float16ExpBias <= float32ExpBias {
+ // Exponent is too small to represent in a Float16 (or a zero). We need to output
+ // denormalized numbers (possibly rounding very small numbers to zero).
+ denorm := float32ExpBias - exp - 1
+ frac += 1 << float32ExpShift
+ frac >>= denorm
+ return sign | Float16(frac)
+ }
+
+ if exp > float32ExpBias+float16ExpBias {
+ // Number too large to represent in a Float16 => round to Infinity.
+ return sign | float16ExpMask
+ }
+
+ // General case.
+ return sign | Float16(((exp+float16ExpBias-float32ExpBias)<<float16ExpShift)|(frac>>13))
+}
+
+func expandF16ToF32(in Float16) uint32 {
+ sign := uint32(in&float16SignMask) << 16
+ frac := uint32(in&float16FracMask) << 13
+ exp := uint32(in&float16ExpMask) >> float16ExpShift
+
+ if exp == 0x1f {
+ // NaN of Infinity
+ return sign | float32ExpMask | frac
+ }
+
+ if exp == 0 {
+ if frac == 0 {
+ // Zero
+ return sign
+ }
+ // Denormalized number. In a float32 it must be stored in a normalized form, so
+ // we normalize it.
+ exp++
+ for frac&float32ExpMask == 0 {
+ frac <<= 1
+ exp--
+ }
+ frac &= float32FracMask
+ }
+
+ exp += (float32ExpBias - float16ExpBias)
+
+ return sign | (exp << float32ExpShift) | frac
}
diff --git a/binary/float16_test.go b/binary/float16_test.go
index ecb6c2f..f1658f2 100644
--- a/binary/float16_test.go
+++ b/binary/float16_test.go
@@ -14,31 +14,84 @@
package binary
-import "testing"
+import (
+ "math"
+ "testing"
+)
+
+var checks = []struct {
+ f16 Float16
+ f32 float32
+}{
+ {0x0000, 0.0},
+ {0x3c00, 1.0},
+ {0x4000, 2.0},
+ {0x4200, 3.0},
+ {0x4400, 4.0},
+ {0x4500, 5.0},
+ {0x3555, 0.333251953125},
+ {0xbc00, -1.0},
+ {0xc000, -2.0},
+ {0xc200, -3.0},
+ {0xc400, -4.0},
+ {0xc500, -5.0},
+ {0xb555, -0.333251953125},
+ {0x0000, 0.0},
+ {0x7a1a, 5e4},
+ {0x068d, 1e-4},
+ {0x0346, 4.995e-5},
+ {0x0053, 4.95e-6},
+ {0x0008, 4.77e-7},
+}
func TestFloat16To32(t *testing.T) {
- checks := []struct {
- f16 Float16
- f32 float32
- }{
- {0x0000, 0.0},
- {0x3c00, 1.0},
- {0x4000, 2.0},
- {0x4200, 3.0},
- {0x4400, 4.0},
- {0x4500, 5.0},
- {0x3555, 0.333251953125},
- {0xbc00, -1.0},
- {0xc000, -2.0},
- {0xc200, -3.0},
- {0xc400, -4.0},
- {0xc500, -5.0},
- {0xb555, -0.333251953125},
- }
for _, c := range checks {
- expected, got := c.f32, c.f16.Float32()
- if expected != got {
- t.Errorf("Expansion of float16(0x%x) to float32 gave unexpected value. Expected: %v, got: %v", c.f16, expected, got)
+ expected, got := float64(c.f32), float64(c.f16.Float32())
+ esign, gsign := math.Signbit(expected), math.Signbit(got)
+ expected, got = math.Abs(expected), math.Abs(got)
+ if esign != gsign || got > expected*1.001 || got < expected*0.999 {
+ t.Errorf("Expansion of float16(0x%04x) to float32 gave unexpected value.\n"+
+ "Expected: %g, got: %g", c.f16, expected, got)
}
}
}
+
+func TestFloat32To16(t *testing.T) {
+ for _, c := range checks {
+ expected, got := c.f16, NewFloat16(c.f32)
+ if expected != got {
+ t.Errorf("Encoding of float32 %v gave unexpected value. Expected: %04x, got: %04x",
+ c.f32, expected, got)
+ }
+ }
+}
+
+func TestFloat16InfTo32(t *testing.T) {
+ if v := NewFloat16Inf(1).Float32(); !math.IsInf(float64(v), 1) {
+ t.Errorf("Positive infinity did not expand to positive infinity, but %v.", v)
+ }
+ if v := NewFloat16Inf(-1).Float32(); !math.IsInf(float64(v), -1) {
+ t.Errorf("Negative infinity did not expand to negative infinity, but %v.", v)
+ }
+ if v := NewFloat16NaN().Float32(); !math.IsNaN(float64(v)) {
+ t.Errorf("NaN constant did not expand to NaN, but %v.", v)
+ }
+}
+
+func TestFloat32InfTo16(t *testing.T) {
+ if v := NewFloat16(float32(math.Inf(1))); !v.IsInf(1) {
+ t.Errorf("Positive infinity did not encode to positive infinity, but %04x.", v)
+ }
+ if v := NewFloat16(float32(math.Inf(-1))); !v.IsInf(-1) {
+ t.Errorf("Negative infinity did not encode to negative infinity, but %04x.", v)
+ }
+ if v := NewFloat16(float32(math.NaN())); !v.IsNaN() {
+ t.Errorf("NaN did not encode to NaN, but %04x.", v)
+ }
+ if v := NewFloat16(float32(1e5)); !v.IsInf(1) {
+ t.Errorf("1e5 did not encode to positive infinity, but %04x.", v)
+ }
+ if v := NewFloat16(5e-8); v != 0 {
+ t.Errorf("5e-8 did not encode to zero, but %04x.", v)
+ }
+}
diff --git a/binary/generate/generate.go b/binary/generate/generate.go
new file mode 100644
index 0000000..5c0fa6a
--- /dev/null
+++ b/binary/generate/generate.go
@@ -0,0 +1,187 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package generate has support for generating encode and decode methods
+// for the binary package automatically.
+package generate
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "fmt"
+ "path"
+ "sort"
+ "strings"
+ "text/template"
+
+ "android.googlesource.com/platform/tools/gpu/binary"
+ "golang.org/x/tools/go/types"
+)
+
+type File struct {
+ Generated string
+ Package string
+ Structs []*Struct
+}
+
+// Struct is a description of an encodable struct.
+// Signature includes the package, name and name and type of all the fields.
+// Any change to the Signature will cause the ID to change.
+type Struct struct {
+ Name string // The simple name of the type.
+ Package string // The package name the struct belongs to.
+ Fields []Field // Descriptions of the fields of the struct.
+ Signature string // The full string type signature of the Struct.
+ ID binary.TypeID // The unique type identifier for the Struct.
+}
+
+// Kind describes the basic nature of a type.
+type Kind int
+
+const (
+ // Native is the kind for primitive types with corresponding direct methods on
+ // Encoder and Decoder
+ Native Kind = iota
+ // Remap is the kind for a type declared as alias to a primitive type.
+ // For example: type U32 uint32.
+ Remap
+ // Codeable is the kind for a direct in place struct.
+ Codeable
+ // Pointer is the kind for a pointer to a struct type. If the struct instance
+ // has equality (==) with a previously encoded object, then this struct will
+ // be encoded as a reference to the first encoded object.
+ Pointer
+ // Array is the kind for an in place slice, with a dynamic length.
+ Array
+ // Interface is the kind for an object boxed in an binary.Object interface
+ // (or superset of). If the object has equality (==) with a previously
+ // encoded object, then this object will be encoded as a reference to the
+ // first encoded object.
+ Interface
+)
+
+// Field holds a description of a single Struct member.
+type Field struct {
+ // Name is the true field name.
+ Name string // The name the field was given.
+ Type *Type // A description of the type of the field.
+}
+
+// Type is used to describe fields of a struct.
+type Type struct {
+ Name string // The name of the type.
+ Native string // The go native name of the type.
+ Kind Kind // The types basic Kind.
+ SubType *Type // If the type is an Array, holds the element type.
+ Method string // The encode/decode method to use.
+}
+
+// FromTypename creates and initializes a Struct from a types.Typename.
+// It assumes that the typename will map to a types.Struct, and adds all the
+// fields of that struct to the Struct information.
+func FromTypename(pkg *types.Package, n *types.TypeName) *Struct {
+ t := n.Type().Underlying().(*types.Struct)
+ s := &Struct{Name: n.Name()}
+ s.Fields = make([]Field, t.NumFields())
+ s.Package = pkg.Name()
+ for i := range s.Fields {
+ decl := t.Field(i)
+ f := &s.Fields[i]
+ f.Name = decl.Name()
+ f.Type = FromType(pkg, decl.Type())
+ }
+ s.updateID()
+ return s
+}
+
+func (s *Struct) updateID() {
+ b := &bytes.Buffer{}
+ fmt.Fprintf(b, "struct %s.%s {", s.Package, s.Name)
+ for i, f := range s.Fields {
+ if i != 0 {
+ fmt.Fprint(b, ",")
+ }
+ fmt.Fprintf(b, " %s:%s", f.Name, f.Type.Name)
+ }
+ fmt.Fprint(b, " }")
+ s.Signature = b.String()
+ s.ID = sha1.Sum([]byte(s.Signature))
+}
+
+// FromType creates a appropriate Type object from a types.Type.
+func FromType(pkg *types.Package, from types.Type) *Type {
+ t := &Type{Name: path.Base(types.TypeString(pkg, from))}
+ if _, isNamed := from.(*types.Named); isNamed {
+ from = from.Underlying()
+ }
+ t.Native = from.String()
+ switch from := from.(type) {
+ case *types.Basic:
+ t.Kind = Native
+ switch from.Kind() {
+ case types.Int:
+ t.Native = "int32"
+ case types.Byte:
+ t.Native = "uint8"
+ }
+ t.Method = strings.Title(t.Native)
+ if t.Native != t.Name {
+ t.Kind = Remap
+ }
+ case *types.Pointer:
+ t.Kind = Pointer
+ t.SubType = FromType(pkg, from.Elem())
+ case *types.Struct:
+ t.Kind = Codeable
+ case *types.Interface:
+ t.Kind = Interface
+ case *types.Slice:
+ t.Kind = Array
+ t.SubType = FromType(pkg, from.Elem())
+ default:
+ panic(fmt.Errorf("Unhandled type %T for field %s", from, t.Name))
+ }
+ return t
+}
+
+// Sort is used to ensure stable ordering of Struct slices.
+// This is to ensure automatically generated code has minimum diffs.
+// The sort order is by Struct name.
+func Sort(structs []*Struct) {
+ sort.Sort(structsByName(structs))
+}
+
+type structsByName []*Struct
+
+func (a structsByName) Len() int { return len(a) }
+func (a structsByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a structsByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
+
+func getTemplate(t *template.Template, name string) *template.Template {
+ result := t.Lookup(name)
+ if result == nil {
+ panic(fmt.Errorf("Could not find template %s", name))
+ }
+ return result
+}
+
+type kindToTemplate map[Kind]*template.Template
+
+func kindDispatch(table kindToTemplate, name string, t *Type) string {
+ b := &bytes.Buffer{}
+ if err := table[t.Kind].Execute(b, Field{name, t}); err != nil {
+ panic(err)
+ }
+ return b.String()
+}
diff --git a/binary/generate/generate_test.go b/binary/generate/generate_test.go
new file mode 100644
index 0000000..89202e2
--- /dev/null
+++ b/binary/generate/generate_test.go
@@ -0,0 +1,159 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package generate
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "testing"
+
+ "golang.org/x/tools/go/loader"
+ "golang.org/x/tools/go/types"
+)
+
+func parseStructs(source string) []*Struct {
+ config := loader.Config{}
+ fakeFile := fmt.Sprintf("package fake\n%s", source)
+ file, err := config.ParseFile("", fakeFile)
+ if err != nil {
+ log.Fatalf("invalid source: %s", err)
+ }
+ config.CreateFromFiles("", file)
+ info, err := config.Load()
+ if err != nil {
+ log.Fatalf("load failed: %s", err)
+ }
+ result := []*Struct{}
+ for _, pkg := range info.Created {
+ for _, def := range pkg.Defs {
+ if n, ok := def.(*types.TypeName); ok {
+ if t, ok := n.Type().(*types.Named); ok {
+ if _, ok := t.Underlying().(*types.Struct); ok {
+ result = append(result, FromTypename(pkg.Pkg, n))
+ }
+ }
+ }
+ }
+ }
+ return result
+}
+
+func parseStruct(t *testing.T, name string, source string) *Struct {
+ s := parseStructs(source)
+ if len(s) != 1 {
+ log.Fatalf("Parsed %d structs, expected 1", len(s))
+ }
+ if s[0].Name != name {
+ t.Errorf("Got struct %s, expected %s", s[0].Name, name)
+ }
+ return s[0]
+}
+
+func TestEmpty(t *testing.T) {
+ s := parseStruct(t, "MyStruct", "type MyStruct struct {}")
+ if len(s.Fields) != 0 {
+ t.Errorf("Got %d fields, expected none", len(s.Fields))
+ }
+}
+
+func TestStableID(t *testing.T) {
+ source := "type MyStruct struct {}"
+ a := parseStruct(t, "MyStruct", source)
+ b := parseStruct(t, "MyStruct", source)
+ if a.ID != b.ID {
+ t.Errorf("ID was not stable")
+ }
+}
+
+func TestNameAffectsID(t *testing.T) {
+ a := parseStruct(t, "MyStruct", "type MyStruct struct {}")
+ b := parseStruct(t, "YourStruct", "type YourStruct struct {}")
+ if a.ID == b.ID {
+ t.Errorf("Name change did not change ID")
+ }
+}
+
+func TestFieldCountAffectsID(t *testing.T) {
+ a := parseStruct(t, "MyStruct", "type MyStruct struct { a int}")
+ b := parseStruct(t, "MyStruct", "type MyStruct struct {}")
+ if a.ID == b.ID {
+ t.Errorf("Field count did not change ID")
+ }
+}
+
+func TestFieldNameAffectsID(t *testing.T) {
+ a := parseStruct(t, "MyStruct", "type MyStruct struct { a int}")
+ b := parseStruct(t, "MyStruct", "type MyStruct struct { b int}")
+ if a.ID == b.ID {
+ t.Errorf("Field name did not change ID")
+ }
+}
+
+func TestFieldTypeAffectsID(t *testing.T) {
+ a := parseStruct(t, "MyStruct", "type MyStruct struct { a int}")
+ b := parseStruct(t, "MyStruct", "type MyStruct struct { a byte}")
+ if a.ID == b.ID {
+ t.Errorf("Field type did not change ID")
+ }
+}
+
+func TestTypes(t *testing.T) {
+ fields := []Field{
+ {"a", &Type{"uint8", "uint8", Basic, nil, "Uint8"}},
+ {"b", &Type{"uint16", "uint16", Basic, nil, "Uint16"}},
+ {"c", &Type{"uint32", "uint32", Basic, nil, "Uint32"}},
+ {"d", &Type{"uint64", "uint64", Basic, nil, "Uint64"}},
+ {"e", &Type{"int8", "int8", Basic, nil, "Int8"}},
+ {"f", &Type{"int16", "int16", Basic, nil, "Int16"}},
+ {"g", &Type{"int32", "int32", Basic, nil, "Int32"}},
+ {"h", &Type{"int64", "int64", Basic, nil, "Int64"}},
+ {"i", &Type{"float32", "float32", Basic, nil, "Float32"}},
+ {"j", &Type{"float64", "float64", Basic, nil, "Float64"}},
+ {"k", &Type{"byte", "uint8", Basic, nil, "Uint8"}},
+ {"l", &Type{"int", "int32", Basic, nil, "Int32"}},
+ {"m", &Type{"bool", "bool", Basic, nil, "Bool"}},
+ {"n", &Type{"string", "string", Basic, nil, "String"}},
+ {"o", &Type{"struct{}", "struct{}", Codeable, nil, ""}},
+ {"p", &Type{"*struct{}", "*struct{}", Pointer, nil, ""}},
+ {"q", &Type{"[]struct{}", "[]struct{}", Array, nil, ""}},
+ {"r", &Type{"interface{}", "interface{}", Interface, nil, ""}},
+ }
+ source := &bytes.Buffer{}
+ fmt.Fprint(source, "type MyStruct struct {\n")
+ for _, f := range fields {
+ fmt.Fprintf(source, " %s %s\n", f.Name, f.Type.Name)
+ }
+ fmt.Fprint(source, "}\n")
+ s := parseStruct(t, "MyStruct", source.String())
+ if len(s.Fields) != len(fields) {
+ t.Errorf("Got %d fields, expected %d", len(s.Fields), len(fields))
+ }
+ for i, got := range s.Fields {
+ expected := fields[i]
+ if got.Name != expected.Name {
+ t.Errorf("Got field %s, expected %s", got.Name, expected.Name)
+ }
+ if got.Type.Kind != expected.Type.Kind {
+ t.Errorf("Got field kind %d, expected %d", got.Type.Kind, expected.Type.Kind)
+ }
+ if got.Type.Native != expected.Type.Native {
+ t.Errorf("Got field native type %s, expected %s", got.Type.Native, expected.Type.Native)
+ }
+ if got.Type.Method != expected.Type.Method {
+ t.Errorf("Got field native type %s, expected %s", got.Type.Method, expected.Type.Method)
+ }
+ }
+}
diff --git a/binary/generate/go.go b/binary/generate/go.go
new file mode 100644
index 0000000..ed2ee7c
--- /dev/null
+++ b/binary/generate/go.go
@@ -0,0 +1,196 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package generate
+
+import (
+ "bytes"
+ "io"
+ "text/template"
+
+ "golang.org/x/tools/imports"
+)
+
+var (
+ goTemplates = template.Must(template.New("").Funcs(goFuncs).Parse(`
+{{define "Register"}} //{{.Signature}}
+ binary.Register(binary.TypeID{ {{range .ID}}{{printf "0x%2.2x" .}}, {{end}} }, &{{.Name}}{})
+{{end}}
+
+{{define "Encoder"}}
+ func (o {{.Name}}) Encode(e *binary.Encoder) error {
+ {{range .Fields}}{{encode (print "o." .Name) .Type}}{{end}}
+ return nil
+ }
+{{end}}
+
+{{define "EncodeNative"}}
+ if err := e.{{.Type.Method}}({{.Name}}); err != nil {
+ return err
+}{{end}}
+
+{{define "EncodeRemap"}}
+ if err := e.{{.Type.Method}}({{.Type.Native}}({{.Name}})); err != nil {
+ return err
+}{{end}}
+
+{{define "EncodeCodeable"}}
+ if err := {{.Name}}.Encode(e); err != nil {
+ return err
+}{{end}}
+
+{{define "EncodeObject"}}
+ if {{.Name}} != nil {
+ if err := e.Object({{.Name}}); err != nil {
+ return err
+ }
+ } else if err := e.Object(nil); err != nil {
+ return err
+}{{end}}
+
+{{define "EncodeArray"}}
+ if err := e.Int32(int32(len({{.Name}}))); err != nil {
+ return err
+ }
+ for i := range {{.Name}} {
+ {{encode (print .Name "[i]") .Type.SubType}}
+}{{end}}
+
+{{define "Decoder"}}
+ func (o *{{.Name}}) Decode(d *binary.Decoder) error {
+ {{range .Fields}}{{decode (print "o." .Name) .Type}}{{end}}
+ return nil
+}{{end}}
+
+{{define "DecodeNative"}}
+ if obj, err := d.{{.Type.Method}}(); err != nil {
+ return err
+ } else {
+ {{.Name}} = {{.Type.Name}}(obj)
+}{{end}}
+
+{{define "DecodeCodeable"}}
+ if err := {{.Name}}.Decode(d); err != nil {
+ return err
+}{{end}}
+
+{{define "DecodeObject"}}
+ if obj, err := d.Object(); err != nil {
+ return err
+ } else if obj != nil {
+ {{.Name}} = obj.({{.Type.Name}})
+ } else {
+ {{.Name}} = nil
+}{{end}}
+
+{{define "DecodeArray"}}
+ if count, err := d.Int32(); err != nil {
+ return err
+ } else {
+ {{.Name}} = make({{.Type.Name}}, count)
+ for i := range {{.Name}} {
+ {{decode (print .Name "[i]") .Type.SubType}}
+ }
+}{{end}}
+
+{{define "File"}}
+////////////////////////////////////////////////////////////////////////////////
+// Do not modify!
+// Generated by {{$.Generated}}
+////////////////////////////////////////////////////////////////////////////////
+
+package {{.Package}}
+
+import (
+ "android.googlesource.com/platform/tools/gpu/binary"
+)
+
+func init() {
+ {{range .Structs}}{{template "Register" .}}{{end}}
+}
+
+{{range .Structs}}
+ {{template "Encoder" .}}
+ {{template "Decoder" .}}
+{{end}}
+
+{{end}}
+ `))
+ goFuncs = template.FuncMap{
+ "encode": func(name string, t *Type) string {
+ return kindDispatch(goEncodeMap, name, t)
+ },
+ "decode": func(name string, t *Type) string {
+ return kindDispatch(goDecodeMap, name, t)
+ },
+ }
+ goEncodeMap kindToTemplate
+ goDecodeMap kindToTemplate
+ goFile *template.Template
+ goRegister *template.Template
+ goEncoder *template.Template
+ goDecoder *template.Template
+)
+
+func init() {
+ goFile = getTemplate(goTemplates, "File")
+ goRegister = getTemplate(goTemplates, "Register")
+ goEncoder = getTemplate(goTemplates, "Encoder")
+ goDecoder = getTemplate(goTemplates, "Decoder")
+ goEncodeMap = kindToTemplate{
+ Native: getTemplate(goTemplates, "EncodeNative"),
+ Remap: getTemplate(goTemplates, "EncodeRemap"),
+ Codeable: getTemplate(goTemplates, "EncodeCodeable"),
+ Pointer: getTemplate(goTemplates, "EncodeObject"),
+ Interface: getTemplate(goTemplates, "EncodeObject"),
+ Array: getTemplate(goTemplates, "EncodeArray"),
+ }
+ goDecodeMap = kindToTemplate{
+ Native: getTemplate(goTemplates, "DecodeNative"),
+ Remap: getTemplate(goTemplates, "DecodeNative"),
+ Codeable: getTemplate(goTemplates, "DecodeCodeable"),
+ Pointer: getTemplate(goTemplates, "DecodeObject"),
+ Interface: getTemplate(goTemplates, "DecodeObject"),
+ Array: getTemplate(goTemplates, "DecodeArray"),
+ }
+}
+
+// GoFile generates the all the go code for a file with a set of structs.
+func GoFile(file *File) ([]byte, error) {
+ b := &bytes.Buffer{}
+ if err := goFile.Execute(b, file); err != nil {
+ return nil, err
+ }
+ result, err := imports.Process("", b.Bytes(), nil)
+ if err != nil {
+ return b.Bytes(), nil
+ }
+ return result, nil
+}
+
+// GoRegister generates the go code to register a Struct with the system,
+// writing it to an io.Writer.
+func GoRegister(w io.Writer, s *Struct) error {
+ return goRegister.Execute(w, s)
+}
+
+// GoEncoder generates an encoder for a Struct, writing it to an io.Writer.
+func GoEncoder(w io.Writer, s *Struct) error {
+ return goEncoder.Execute(w, s)
+}
+
+// GoEncoder generates a decoder for a Struct, writing it to an io.Writer.
+func GoDecoder(w io.Writer, s *Struct) error {
+ return goDecoder.Execute(w, s)
+}
diff --git a/binary/generate/java.go b/binary/generate/java.go
new file mode 100644
index 0000000..9a2d9f3
--- /dev/null
+++ b/binary/generate/java.go
@@ -0,0 +1,175 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package generate
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+ "text/template"
+ "unicode"
+ "unicode/utf8"
+)
+
+var (
+ javaTemplates = template.Must(template.New("").Funcs(javaFuncs).Parse(`
+{{define "Enum"}}{{.Name}}Enum{{end}}
+{{define "ID"}}{{.Name}}ID{{end}}
+{{define "IDBytes"}}{{.Name}}IDBytes{{end}}
+
+{{define "Encoder"}}
+ public static void encode(Encoder e, {{class .Name}} o) throws IOException {
+ {{range .Fields}} {{encode (print "o." .Name) .Type}}
+ {{end}}} {{end}}
+
+{{define "EncodeNative"}}e.{{lower .Type.Method}}({{.Name}});{{end}}
+{{define "EncodeRemap"}}{{.Name}}.encode(e);{{end}}
+{{define "EncodeCodeable"}}{{.Name}}.encode(e);{{end}}
+{{define "EncodeObject"}}e.object({{.Name}});{{end}}
+
+{{define "EncodeArray"}} e.int32({{.Name}}.length);
+ for (int i = 0; i < {{.Name}}.length; i++) {
+ {{encode (print .Name "[i]") .Type.SubType}}
+ }
+{{end}}
+
+{{define "Decoder"}}
+ public static void decode(Decoder d, {{class .Name}} o) throws IOException {
+ {{range .Fields}} {{decode (print "o." .Name) .Type}}
+ {{end}}} {{end}}
+
+{{define "DecodeNative"}}{{.Name}} = d.{{lower .Type.Method}}();{{end}}
+{{define "DecodeRemap"}}{{.Name}} = {{.Type.Name}}.decode(d);{{end}}
+{{define "DecodeCodeable"}}{{.Name}} = new {{.Type.Name}}(d);{{end}}
+{{define "DecodeObject"}}{{.Name}} = ({{storage .Type}})d.object();{{end}}
+
+{{define "DecodeArray"}} {{.Name}} = new {{storage .Type.SubType}}[d.int32()];
+ for (int i = 0; i < {{.Name}}.length; i++) {
+ {{decode (print .Name "[i]") .Type.SubType}}
+ }
+{{end}}
+
+{{define "File"}}
+////////////////////////////////////////////////////////////////////////////////
+// Do not modify!
+// Generated by {{$.Generated}}
+////////////////////////////////////////////////////////////////////////////////
+package {{.Package}};
+
+import com.android.tools.idea.gfx.binary.BinaryObject;
+import com.android.tools.idea.gfx.binary.ObjectTypeID;
+import com.android.tools.idea.gfx.binary.BinaryObjectCreator;
+import com.android.tools.idea.gfx.binary.Decoder;
+import com.android.tools.idea.gfx.binary.Encoder;
+import java.io.IOException;
+
+class ObjectFactory {
+ public enum Entries implements BinaryObjectCreator { {{range .Structs}}
+ {{template "Enum" .}} {
+ @Override public BinaryObject create() { return new {{class .Name}}(); }
+ }, {{end}}
+ }
+ {{range .Structs}}
+ public static byte[] {{template "IDBytes" .}} = { {{range .ID}}{{toS8 .}}, {{end}} };
+ public static ObjectTypeID {{template "ID" .}} = new ObjectTypeID({{template "IDBytes" .}}); {{end}}
+
+ static { {{range .Structs}}
+ ObjectTypeID.register({{template "ID" .}}, Entries.{{template "Enum" .}});{{end}}
+ }
+
+ {{range .Structs}}
+ {{template "Encoder" .}}
+ {{template "Decoder" .}}
+ {{end}}
+}
+
+{{end}}
+ `))
+ javaFuncs = template.FuncMap{
+ "encode": func(name string, t *Type) string {
+ return kindDispatch(javaEncodeMap, name, t)
+ },
+ "decode": func(name string, t *Type) string {
+ return kindDispatch(javaDecodeMap, name, t)
+ },
+ "lower": strings.ToLower,
+ "fieldname": func(s string) string {
+ r, n := utf8.DecodeRuneInString(s)
+ return string(unicode.ToLower(r)) + s[n:]
+ },
+ "toS8": func(val byte) string { return fmt.Sprint(int8(val)) },
+ "storage": func(t *Type) string {
+ name := t.Name
+ if t.Kind == Pointer {
+ name = t.SubType.Name
+ }
+ if result, ok := javaTypeMap[name]; ok {
+ return result
+ }
+ return name
+ },
+ "class": func(name string) string {
+ if strings.HasPrefix(name, "call") {
+ return fmt.Sprintf("Commands.%s.Call", name[4:])
+ }
+ if strings.HasPrefix(name, "result") {
+ return fmt.Sprintf("Commands.%s.Result", name[6:])
+ }
+ return name
+ },
+ }
+ javaEncodeMap kindToTemplate
+ javaDecodeMap kindToTemplate
+ javaFile *template.Template
+ javaTypeMap = map[string]string{
+ "int8": "byte",
+ "uint8": "short",
+ "int16": "short",
+ "uint16": "int",
+ "int32": "int",
+ "uint32": "long",
+ "int64": "long",
+ "uint64": "long",
+ "float32": "float",
+ "float64": "double",
+ }
+)
+
+func init() {
+ javaFile = getTemplate(javaTemplates, "File")
+ javaEncodeMap = kindToTemplate{
+ Native: getTemplate(javaTemplates, "EncodeNative"),
+ Remap: getTemplate(javaTemplates, "EncodeRemap"),
+ Codeable: getTemplate(javaTemplates, "EncodeCodeable"),
+ Pointer: getTemplate(javaTemplates, "EncodeObject"),
+ Interface: getTemplate(javaTemplates, "EncodeObject"),
+ Array: getTemplate(javaTemplates, "EncodeArray"),
+ }
+ javaDecodeMap = kindToTemplate{
+ Native: getTemplate(javaTemplates, "DecodeNative"),
+ Remap: getTemplate(javaTemplates, "DecodeRemap"),
+ Codeable: getTemplate(javaTemplates, "DecodeCodeable"),
+ Pointer: getTemplate(javaTemplates, "DecodeObject"),
+ Interface: getTemplate(javaTemplates, "DecodeObject"),
+ Array: getTemplate(javaTemplates, "DecodeArray"),
+ }
+}
+
+// JavaFile generates the all the java code for a file with a set of structs.
+func JavaFile(file *File) ([]byte, error) {
+ b := &bytes.Buffer{}
+ err := javaFile.Execute(b, file)
+ return b.Bytes(), err
+}
diff --git a/binary/object.go b/binary/object.go
index f99cccc..9234fb6 100644
--- a/binary/object.go
+++ b/binary/object.go
@@ -62,3 +62,37 @@
}
idToType[id] = t.Elem()
}
+
+type unknownType struct {
+ Object Encodable
+}
+
+func (e unknownType) Error() string {
+ return fmt.Sprintf("Unknown type %T encountered in binary.TypeOf", e.Object)
+}
+
+// Given an encodable object return the TypeID for that type of object.
+// If there is no TypeID for this type of object, return a non-nil error.
+func TypeOf(obj Encodable) (TypeID, error) {
+ id, idFound := typeToID[reflect.TypeOf(obj)]
+ if !idFound {
+ return TypeID{}, unknownType{obj}
+ }
+ return id, nil
+}
+
+type unknownTypeID TypeID
+
+func (e unknownTypeID) Error() string {
+ return fmt.Sprintf("Unknown type id %x encountered in binary.MakeObject", TypeID(e))
+}
+
+// Given a TypeID return a zero value instance of the object type.
+// If this TypeID is not for a registered type, return a non-nil error.
+func MakeObject(typeId TypeID) (Decodable, error) {
+ t, idFound := idToType[typeId]
+ if !idFound {
+ return nil, unknownTypeID(typeId)
+ }
+ return reflect.New(t).Interface().(Decodable), nil
+}