Skip to content

transform: rework arrays

Hugo Moreau requested to merge hm/arrays into master

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:

/*
 * 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 ArrayRecords 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

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

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

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

var foo [3]int

↓↓↓

var foo_0, foo_1, foo_2 int

Array Initialization

foo := [3][2]int{[2]int{0, 1}, [2]int{2, 3}, [2]int{4, 5}}

↓↓↓

foo_0, foo_1, foo_2, foo_3, foo_4, foo_5 := 0, 1, 2, 3, 4, 5

Array Copy

var foo [3]int = bar
foo := bar

↓↓↓

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

x := foo[0]
foo[1] = x

↓↓↓

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

Merge request reports