Skip to content

Integrating structs and interfaces in go2pins

Hugo Moreau requested to merge hm/objects into master

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)
        }
}
Edited by Hugo Moreau

Merge request reports