Integrating structs and interfaces in go2pins
Integrating structs and interfaces in go2pins
This merge request is blocked by the array handling merge request (https://gitlab.lrde.epita.fr/spot/go2pins/-/merge_requests/5).
Structs
The main idea behing struct
handling is the following:
Each struct is continuous memory area, it can be seen as an array, therefore
every struct
will be converted into a simple array.
We took care of handling struct
declarations, methods, fields,
literals.
Detect
As https://gitlab.lrde.epita.fr/spot/go2pins/-/merge_requests/5, we used the same techniques, detect and transform. We decided to detect any struct declarations:
- TypeSpec
type s struct { x int }
- ValueSpec
var v struct{ x int}
- Anonymous
v := struct{x int}{}
You can find their implementation with the following functions:
func (m *Meta) AddStructViaType(ts *ast.TypeSpec, fn *ast.Ident) *StructRecord
func (m *Meta) AddStructViaValue(vs *ast.ValueSpec, fn *ast.Ident) *StructRecord
func (m *Meta) AddStructAnonymously(cl *ast.CompositeLit, fn *ast.Ident) *StructRecord
We basicly strore this information:
// StructRecord represents a transformed struct in store.
type StructRecord struct {
StructType *ast.StructType
Index int
OriginalIdent *ast.Ident // Can be null with anonymous struct
Ident *ast.Ident
Fields []*ast.Field
Function *ast.Ident
Variables []*ast.Ident
Size int
}
The size being calculated depending on all of the struct
fields.
Transform
As we transform each struct
into a simple array
, for a better handling, we
will make the first index of our array, an index representing the struct
(for go2pins
, its internal index).
Example
Struct declaration
type Foo struct {
x, y int
}
↓↓↓
var struct_Foo int = 1
Struct variable declarations
var X Foo
var X Foo = Foo{}
var X Foo = Foo{1, 2}
var X Foo = Foo{y: 1}
X := Foo{}
↓↓↓
var X [3]int = [3]int{1, 0, 0}
var X [3]int = [3]int{1, 0, 0}
var X [3]int = [3]int{1, 1, 2}
var X [3]int = [3]int{1, 0, 1}
X := [3]int{1, 0, 0}
Struct Fields access
println(X.x)
↓↓↓
println(X[1])
Struct Argument
func foo(x Foo) {}
foo(X)
↓↓↓
func foo(x [3]int) {}
foo(X)
Struct Method
func (f Foo) foo(x int) {}
X.foo()
↓↓↓
func Foo_foo(f [3]int, x int) {}
Foo_foo(X)
Corner case to treat
Self containing struct (Done) Anything copying other thing (done) (init with copy of other struct done, init with copy of int done) Handling array (Need to finish) (Copying array automatically treated by array transform)
Interface
Handling struct
being done, interface
works slightly as same as struct
in
the way that an interface
variable is a struct
.
Detect
In go
, any
or interface{}
is an interface
allowing any type.
We will detect any interface
and register them in a vector to use them. After
registering them, we will use the data registered for the struct
and will
associates them to the correct interface
.
This way we will be able to know dynamically which interface is which.
An interface will have a size according to the maximum of all its underlying type size.
Transform
Example
Interface declaration
type Speaker interface { Say() }
↓↓↓
var Speaker_interface int = 1
Interface Dynamic Dispatch
type Human struct{}
type Dog struct{}
func (h Human) Say() { println("Hello there!") }
func (d Dog) Say() { println("Bark bark!") }
func main() {
var s Speaker
for i := 0; i < 20; i++ {
if i%2 == 0 {
s = Dog{}
} else {
s = Human{}
}
s.Say()
}
}
↓↓↓
var ( // Structs
Human_struct int = 1
Dog_struct int = 2
)
func Human_Say(h [1]int) { println("Hello there!") }
func Dog_Say(d [1]int) { println("Bark bark!") }
func Speaker_Dispatcher_Say(s [1]int) {
if s[0] == Human_struct {
Human_Say(s)
} else if s[0] == Dog_struct {
Dog_Say(s)
}
}
func main() {
var s [1]int
for i := 0; i < 20; i++ {
if i%2 == 0 {
s = [1]int{1}
} else {
s = [1]int{2}
}
Speaker_Dispatcher_Say(s)
}
}