go2pins merge requestshttps://gitlab.lre.epita.fr/spot/go2pins/-/merge_requests2019-07-19T15:28:39+02:00https://gitlab.lre.epita.fr/spot/go2pins/-/merge_requests/2Er/cleanup2019-07-19T15:28:39+02:00Etienne RenaultEr/cleanuphttps://gitlab.lre.epita.fr/spot/go2pins/-/merge_requests/3Configuring Go2Pins to be called everywhere2021-03-30T08:08:37+02:00Hugo MoreauConfiguring Go2Pins to be called everywhereCalling Go2Pins with `-blackbox-fn` wasn't handled correctly before.
By using go *modules*, we are now able to handles packages creation and using everywhere, especially outside the `go2pins` directory. \
The problem was that we needed t...Calling Go2Pins with `-blackbox-fn` wasn't handled correctly before.
By using go *modules*, we are now able to handles packages creation and using everywhere, especially outside the `go2pins` directory. \
The problem was that we needed to specify our `go2pins` *module* path everytime, and in the case that the `output` directory was created outside the `go2pins` directory, it would have generated a problem.
We go from this:
```go
import "gitlab.lrde.epita.fr/spot/go2pins/output/blackbox"
```
to this:
```go
import "output/blackbox" // output is the output directory name
```
More infos about go *modules* can be find [here](https://blog.golang.org/using-go-modules).
* boilerplate/Makefile, main.go, tools/blackbox.go : Modified.Hugo MoreauHugo Moreauhttps://gitlab.lre.epita.fr/spot/go2pins/-/merge_requests/4boilerplate: include in the binary2022-05-13T08:06:53+02:00Antoine Martinamartin@lrde.epita.frboilerplate: include in the binaryThis should make go2pins distributable as a single static binary (or rather, 2 static binaries, including ltlrec). The `boilerplate/` directory no longer needs to exist on the user's machine.This should make go2pins distributable as a single static binary (or rather, 2 static binaries, including ltlrec). The `boilerplate/` directory no longer needs to exist on the user's machine.https://gitlab.lre.epita.fr/spot/go2pins/-/merge_requests/5transform: rework arrays2022-10-13T11:19:31+02:00Hugo Moreautransform: rework arrays# Array transform
Originally, there was `DesugarArray` transform handling array in Go2Pins, but the process was quite simple and converted arrays into single variables. Only the name of the array was stored.
## Rework
As we use `Meta`...# Array transform
Originally, there was `DesugarArray` transform handling array in Go2Pins, but the process was quite simple and converted arrays into single variables. Only the name of the array was stored.
## Rework
As we use `Meta` to store global informations about our transforms, we decided to rework `Meta` by adding two structs:
```go
/*
* ArrayRecord represents a transformed array in store.
*
* Each elements of any array are transformed into a single int variable.
*/
type ArrayRecord struct {
// The array definition.
Def *ast.ArrayType
// Original Identifier.
Ident *ast.Ident
// Context of the array declaration: if it is declared in a function or
// not.
Context *ast.Object
// Initialization elements.
Elts []ast.Expr
// This field is only set when the initialization is done by copying
// another array.
Copy *ast.Ident
// Array sizes.
Sizes []int
// Array transformed variables.
Var []*ArrayVar
}
/*
* Unique representation of single array variable.
*/
type ArrayVar struct {
// Its identifier.
obj *ast.Object
// Set if a unique variable is associated at creation.
val ast.Expr
// Set if another array is associated at creation.
cpy *ast.Ident
}
```
We decide to store our `ArrayRecord`s in `Meta` as a `map[*ast.Object]*FunctionRecord`.
With these said, we have a unique way of keeping a track on our arrays during all transforms.
## Helper Functions
We are handling three types of array initialization:
- Empty Array
- Array With Starting Values
- Array With Copying Values
Both of these initialization are handled in the `Array` transform and are registered in `Meta`.
### Empty Array
```go
func (m *Meta) AddArrayEmpty(ident *ast.Ident, array *ast.ArrayType, context *ast.Object) *ArrayRecord
```
Identifying an array declaration (`*ast.ValueSpec`) with no Left Hand Side values, we can store our array without any values, and only its size and its context (declared in a scope or not).
### Array With Starting Values
```go
func (m *Meta) AddArrayInit(ident *ast.Ident, value *ast.CompositeLit, context *ast.Object) *ArrayRecord
```
This time, if we identify an array declaration with Left Hand Side, we don't need to pass the `*ast.ArrayType` as we can deduce from its starting values.
### Array With Copying Values
```go
func (m *Meta) AddArrayCopy(ident *ast.Ident, cpy *ast.Ident, context *ast.Object) *ArrayRecord
```
If an array gets its values from another array, we just copy the informations from the array we already have.
This method is used for function declaration using arrays.
## Transform
As we got all our informations stored, we can now apply real transformations on the AST.
The `PostArray` handles it by transforming each declaration, assignment, using of every arrays.
### Example
#### Empty arrays
```go
var foo [3]int
```
↓↓↓
```go
var foo_0, foo_1, foo_2 int
```
#### Array Initialization
```go
foo := [3][2]int{[2]int{0, 1}, [2]int{2, 3}, [2]int{4, 5}}
```
↓↓↓
```go
foo_0, foo_1, foo_2, foo_3, foo_4, foo_5 := 0, 1, 2, 3, 4, 5
```
#### Array Copy
```go
var foo [3]int = bar
foo := bar
```
↓↓↓
```go
var foo_0, foo_1, foo_2 int = bar_0, bar_1, bar_2
foo_0, foo_1, foo_2 := bar_0, bar_1, bar_2
```
#### Index Accessing
```go
x := foo[0]
foo[1] = x
```
↓↓↓
```go
x := foo_0
foo_1 = x
```
## Bad side
As we declare a variable for each arrays index, the `Go` code isn't correct since we may have array variable we don't use.
### To Be Improved
- Code can easily be more factorized, as `*ast.ValueSpec` and `*ast.AssignStmt` are quite the same thing.
- Rework single array using.Hugo MoreauHugo Moreauhttps://gitlab.lre.epita.fr/spot/go2pins/-/merge_requests/7Integrating structs and interfaces in go2pins2022-10-13T11:31:48+02:00Hugo MoreauIntegrating 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...# 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:
```go
func (m *Meta) AddStructViaType(ts *ast.TypeSpec, fn *ast.Ident) *StructRecord
```
```go
func (m *Meta) AddStructViaValue(vs *ast.ValueSpec, fn *ast.Ident) *StructRecord
```
```go
func (m *Meta) AddStructAnonymously(cl *ast.CompositeLit, fn *ast.Ident) *StructRecord
```
We basicly strore this information:
```go
// 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
```go
type Foo struct {
x, y int
}
```
↓↓↓
```go
var struct_Foo int = 1
```
##### Struct variable declarations
```go
var X Foo
var X Foo = Foo{}
var X Foo = Foo{1, 2}
var X Foo = Foo{y: 1}
X := Foo{}
```
↓↓↓
```go
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
```go
println(X.x)
```
↓↓↓
```go
println(X[1])
```
##### Struct Argument
```go
func foo(x Foo) {}
foo(X)
```
↓↓↓
```go
func foo(x [3]int) {}
foo(X)
```
###### Struct Method
```go
func (f Foo) foo(x int) {}
X.foo()
```
↓↓↓
```go
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
```go
type Speaker interface { Say() }
```
↓↓↓
```go
var Speaker_interface int = 1
```
##### Interface Dynamic Dispatch
```go
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()
}
}
```
↓↓↓
```go
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)
}
}
```Hugo MoreauHugo Moreauhttps://gitlab.lre.epita.fr/spot/go2pins/-/merge_requests/6add debug mode for transforms2022-10-13T11:45:57+02:00Hugo Moreauadd debug mode for transforms# Debug mode
It is now possible to visualize every transforms details, by simply adding the options `-debug` when calling go2pins, it will create a `debug/` directory in the `output` directory with all transforms output. Every transform...# Debug mode
It is now possible to visualize every transforms details, by simply adding the options `-debug` when calling go2pins, it will create a `debug/` directory in the `output` directory with all transforms output. Every transforms `go` files is prefixed with its index.
For example, calling `go2pins -debug test.go` would produce:
```
00-transform-alive-1.go
01-transform-waitgroup-1.go
02-trransform-channel-1.go
...
```
# Cleanup main.go
At the same time, main.go was too heavy and has been redesigned to be more comprehensible.
Options are now in `tools/options.go`, the program's entry is now in `tools/entry.go` and the compilation process has been set in `tools/compile.go`.Hugo MoreauHugo Moreauhttps://gitlab.lre.epita.fr/spot/go2pins/-/merge_requests/8ltlrec: adapt to better support PSL, rename to pslrec2022-10-17T15:26:02+02:00Antoine Martinamartin@lrde.epita.frltlrec: adapt to better support PSL, rename to pslrechttps://gitlab.lre.epita.fr/spot/go2pins/-/merge_requests/9fix interface transformation2022-10-19T14:44:25+02:00Hugo Moreaufix interface transformationHugo MoreauHugo Moreau