Repository: Konstantin8105/c4go
Pull request #363 (2019-03-28 08:24:37)

atomic operation for increment pointer


Patch:
diff --git a/ast/alloc_size_attr.go b/ast/alloc_size_attr.go
index cd885bd..e98bbaf 100644
--- a/ast/alloc_size_attr.go
+++ b/ast/alloc_size_attr.go
@@ -23,12 +23,22 @@ func parseAllocSizeAttr(line string) *AllocSizeAttr {
 		line,
 	)
 
+	var av, bv int
+	a := strings.TrimSpace(groups["a"])
+	if a != "" {
+		av = util.Atoi(a)
+	}
+	b := strings.TrimSpace(groups["b"])
+	if b != "" {
+		bv = util.Atoi(b)
+	}
+
 	return &AllocSizeAttr{
 		Addr:        ParseAddress(groups["address"]),
 		Pos:         NewPositionFromString(groups["position"]),
 		IsInherited: len(groups["inherited"]) > 0,
-		A:           util.Atoi(strings.TrimSpace(groups["a"])),
-		B:           util.Atoi(strings.TrimSpace(groups["b"])),
+		A:           av,
+		B:           bv,
 		ChildNodes:  []Node{},
 	}
 }
diff --git a/ast/ast.go b/ast/ast.go
index 36fc50d..a8a6588 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -142,6 +142,8 @@ func Parse(fullline string) (returnNode Node, err error) {
 		return parseElaboratedType(line), nil
 	case "EmptyDecl":
 		return parseEmptyDecl(line), nil
+	case "EnableIfAttr":
+		return parseEnableIfAttr(line), nil
 	case "Enum":
 		return parseEnum(line), nil
 	case "EnumConstantDecl":
@@ -216,6 +218,8 @@ func Parse(fullline string) (returnNode Node, err error) {
 		return parseNotTailCalledAttr(line), nil
 	case "OffsetOfExpr":
 		return parseOffsetOfExpr(line), nil
+	case "OverloadableAttr":
+		return parseOverloadableAttr(line), nil
 	case "PackedAttr":
 		return parsePackedAttr(line), nil
 	case "ParagraphComment":
diff --git a/ast/enable_if_attr.go b/ast/enable_if_attr.go
new file mode 100644
index 0000000..8761ba0
--- /dev/null
+++ b/ast/enable_if_attr.go
@@ -0,0 +1,49 @@
+package ast
+
+// EnableIfAttr is a type of attribute that is optionally attached to a variable
+// or struct field definition.
+type EnableIfAttr struct {
+	Addr        Address
+	Pos         Position
+	Message1    string
+	IsInherited bool
+	ChildNodes  []Node
+}
+
+func parseEnableIfAttr(line string) *EnableIfAttr {
+	groups := groupsFromRegex(
+		`<(?P<position>.*)>(?P<inherited> Inherited)? "(?P<message1>.*?)"`,
+		line,
+	)
+
+	return &EnableIfAttr{
+		Addr:        ParseAddress(groups["address"]),
+		Pos:         NewPositionFromString(groups["position"]),
+		Message1:    removeQuotes(groups["message1"]),
+		IsInherited: len(groups["inherited"]) > 0,
+		ChildNodes:  []Node{},
+	}
+}
+
+// AddChild adds a new child node. Child nodes can then be accessed with the
+// Children attribute.
+func (n *EnableIfAttr) AddChild(node Node) {
+	n.ChildNodes = append(n.ChildNodes, node)
+}
+
+// Address returns the numeric address of the node. See the documentation for
+// the Address type for more information.
+func (n *EnableIfAttr) Address() Address {
+	return n.Addr
+}
+
+// Children returns the child nodes. If this node does not have any children or
+// this node does not support children it will always return an empty slice.
+func (n *EnableIfAttr) Children() []Node {
+	return n.ChildNodes
+}
+
+// Position returns the position in the original source code.
+func (n *EnableIfAttr) Position() Position {
+	return n.Pos
+}
diff --git a/ast/overloadable_attr.go b/ast/overloadable_attr.go
new file mode 100644
index 0000000..6f0e5e6
--- /dev/null
+++ b/ast/overloadable_attr.go
@@ -0,0 +1,45 @@
+package ast
+
+// OverloadableAttr is a type of attribute that is optionally attached to a variable
+// or struct field definition.
+type OverloadableAttr struct {
+	Addr       Address
+	Pos        Position
+	ChildNodes []Node
+}
+
+func parseOverloadableAttr(line string) *OverloadableAttr {
+	groups := groupsFromRegex(
+		"<(?P<position>.*)>",
+		line,
+	)
+
+	return &OverloadableAttr{
+		Addr:       ParseAddress(groups["address"]),
+		Pos:        NewPositionFromString(groups["position"]),
+		ChildNodes: []Node{},
+	}
+}
+
+// AddChild adds a new child node. Child nodes can then be accessed with the
+// Children attribute.
+func (n *OverloadableAttr) AddChild(node Node) {
+	n.ChildNodes = append(n.ChildNodes, node)
+}
+
+// Address returns the numeric address of the node. See the documentation for
+// the Address type for more information.
+func (n *OverloadableAttr) Address() Address {
+	return n.Addr
+}
+
+// Children returns the child nodes. If this node does not have any children or
+// this node does not support children it will always return an empty slice.
+func (n *OverloadableAttr) Children() []Node {
+	return n.ChildNodes
+}
+
+// Position returns the position in the original source code.
+func (n *OverloadableAttr) Position() Position {
+	return n.Pos
+}
diff --git a/ast/position.go b/ast/position.go
index 8027fa6..8f49e19 100644
--- a/ast/position.go
+++ b/ast/position.go
@@ -302,6 +302,8 @@ func setPosition(node Node, position Position) {
 		n.Pos = position
 	case *EmptyDecl:
 		n.Pos = position
+	case *EnableIfAttr:
+		n.Pos = position
 	case *EnumConstantDecl:
 		n.Pos = position
 	case *EnumDecl:
@@ -366,6 +368,8 @@ func setPosition(node Node, position Position) {
 		n.Pos = position
 	case *OffsetOfExpr:
 		n.Pos = position
+	case *OverloadableAttr:
+		n.Pos = position
 	case *PackedAttr:
 		n.Pos = position
 	case *ParagraphComment:
diff --git a/main.go b/main.go
index cba528a..e58c6ea 100644
--- a/main.go
+++ b/main.go
@@ -493,7 +493,7 @@ func generateGoCode(args ProgramArgs, lines []string, filePP preprocessor.FilePP
 
 	// simplify Go code by `gofmt`
 	// error ignored, because it is not change the workflow
-	_, _ = exec.Command("gofmt", "-w", outputFilePath).Output()
+	_, _ = exec.Command("gofmt", "-s", "-w", outputFilePath).Output()
 
 	return nil
 }
diff --git a/program/struct.go b/program/struct.go
index 405e8fb..e28905e 100644
--- a/program/struct.go
+++ b/program/struct.go
@@ -29,6 +29,10 @@ type Struct struct {
 	// Each of the fields and their C type. The field may be a string or an
 	// instance of Struct for nested structures.
 	Fields map[string]interface{}
+
+	// int    - position of field
+	// string - name of field
+	FieldNames map[int]string
 }
 
 // NewStruct creates a new Struct definition from an ast.RecordDecl.
@@ -42,14 +46,18 @@ func NewStruct(p *Program, n *ast.RecordDecl) (st *Struct, err error) {
 		}
 	}()
 	fields := make(map[string]interface{})
+	names := map[int]string{}
 
+	counter := 0
 	for _, field := range n.Children() {
 		switch f := field.(type) {
 		case *ast.FieldDecl:
 			fields[f.Name] = f.Type
+			names[counter] = f.Name
 
 		case *ast.IndirectFieldDecl:
 			fields[f.Name] = f.Type
+			names[counter] = f.Name
 
 		case *ast.RecordDecl:
 			fields[f.Name], err = NewStruct(p, f)
@@ -69,6 +77,7 @@ func NewStruct(p *Program, n *ast.RecordDecl) (st *Struct, err error) {
 			err = fmt.Errorf("cannot decode: %#v", f)
 			return
 		}
+		counter++
 	}
 
 	var t TypeOfStruct
@@ -85,10 +94,11 @@ func NewStruct(p *Program, n *ast.RecordDecl) (st *Struct, err error) {
 	}
 
 	return &Struct{
-		Name:     n.Name,
-		IsGlobal: p.Function == nil,
-		Type:     t,
-		Fields:   fields,
+		Name:       n.Name,
+		IsGlobal:   p.Function == nil,
+		Type:       t,
+		Fields:     fields,
+		FieldNames: names,
 	}, nil
 }
 
diff --git a/scripts/scripts.txt b/scripts/scripts.txt
index 1821ccc..f9b9798 100644
--- a/scripts/scripts.txt
+++ b/scripts/scripts.txt
@@ -11,12 +11,12 @@ Calculate warnings : ./testdata/ed
 
 Calculate warnings in file: ./testdata/neateqn/neateqn.go
 		After transpiling : 0 warnings.
-		Go build : 0 warnings
+		Go build : 5 warnings
 		Unsafe   : 22
 
 Calculate warnings in file: ./testdata/neatmkfn/neatmkfn.go
 		After transpiling : 557 warnings.
-		Go build : 75 warnings
+		Go build : 72 warnings
 		Unsafe   : 44
 
 Calculate warnings in file: ./testdata/neatpost/neatpost.go
@@ -31,12 +31,12 @@ Calculate warnings in file: ./testdata/neatrefer/neatrefer.go
 
 Calculate warnings in file: ./testdata/neatroff/neatroff.go
 		After transpiling : 6 warnings.
-		Go build : 22 warnings
+		Go build : 25 warnings
 		Unsafe   : 202
 
 Calculate warnings in file: ./testdata/neatvi/neatvi.go
 		After transpiling : 34 warnings.
-		Go build : 2 warnings
+		Go build : 12 warnings
 		Unsafe   : 130
 
 Calculate warnings in file: testdata/vorbis/vorbis.go
diff --git a/transpiler/unary.go b/transpiler/unary.go
index d1e0125..b7cd93a 100644
--- a/transpiler/unary.go
+++ b/transpiler/unary.go
@@ -21,6 +21,9 @@ func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operato
 		if err != nil {
 			err = fmt.Errorf("Cannot transpileUnaryOperatorInc. err = %v", err)
 		}
+		if eType == "" {
+			eType = "EmptyTypeInUnaryOperatorInc"
+		}
 	}()
 
 	if !(operator == token.INC || operator == token.DEC) {
@@ -78,7 +81,20 @@ func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operato
 		}, p, false)
 	}
 
-	return transpileBinaryOperator(&ast.BinaryOperator{
+	// from:
+	// 		*w++
+	// to:
+	// 		func () []byte {
+	//			defer func(){
+	//				*w = *w + 1 // binary
+	//			}()
+	//			tempVar := *w
+	//			return tempVar
+	// 		}
+	varName := "tempVarUnary"
+
+	v, vType, _, _, _ := transpileToExpr(n.ChildNodes[0], p, false)
+	incExpr, _, newPre, newPost, err := transpileBinaryOperator(&ast.BinaryOperator{
 		Type:     n.Type,
 		Operator: "=",
 		ChildNodes: []ast.Node{
@@ -93,6 +109,35 @@ func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operato
 			},
 		},
 	}, p, false)
+	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
+	if err != nil {
+		return
+	}
+
+	var exprResolveType string
+	exprResolveType, err = types.ResolveType(p, vType)
+	if err != nil {
+		return
+	}
+
+	expr = util.NewAnonymousFunction(
+		// body :
+		append(preStmts, &goast.AssignStmt{
+			Lhs: []goast.Expr{util.NewIdent(varName)},
+			Tok: token.DEFINE,
+			Rhs: []goast.Expr{v},
+		}),
+		// defer :
+		[]goast.Stmt{
+			&goast.ExprStmt{X: incExpr},
+		},
+		// return :
+		util.NewIdent(varName),
+		exprResolveType)
+
+	eType = n.Type
+
+	return
 }
 
 func transpileUnaryOperatorNot(n *ast.UnaryOperator, p *program.Program) (
diff --git a/transpiler/variables.go b/transpiler/variables.go
index 27a5e1b..dfc6503 100644
--- a/transpiler/variables.go
+++ b/transpiler/variables.go
@@ -184,6 +184,18 @@ func GenerateFuncType(fields, returns []string) *goast.FuncType {
 	return &ft
 }
 
+// tranpileInitListExpr.
+//
+// Examples:
+//
+// -InitListExpr 0x3cea0f0 <col:29, line:54:1> 'char *[256]'
+//  |-array filler
+//  | `-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *'
+//  |-ImplicitCastExpr 0x3cea138 <line:51:10> 'char *' <ArrayToPointerDecay>
+//  | `-StringLiteral 0x3ce9f00 <col:10> 'char [3]' lvalue "fa"
+//  |-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *'
+//  |-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *'
+//
 func transpileInitListExpr(e *ast.InitListExpr, p *program.Program) (
 	expr goast.Expr, exprType string, err error) {
 	defer func() {
@@ -192,79 +204,136 @@ func transpileInitListExpr(e *ast.InitListExpr, p *program.Program) (
 		}
 	}()
 	resp := []goast.Expr{}
-	var hasArrayFiller = false
 	e.Type1 = util.GenerateCorrectType(e.Type1)
 	e.Type2 = util.GenerateCorrectType(e.Type2)
+	exprType = e.Type1
 
-	for _, node := range e.Children() {
+	structType, isStruct := p.Structs[e.Type1]
+	if !isStruct {
+		if tt, ok := p.GetBaseTypeOfTypedef(e.Type1); ok {
+			structType, isStruct = p.Structs[tt]
+		}
+	}
+
+	for fieldPos, node := range e.Children() {
 		// Skip ArrayFiller
 		if _, ok := node.(*ast.ArrayFiller); ok {
-			hasArrayFiller = true
 			continue
 		}
 
 		var expr goast.Expr
+		var eType string
 		var err error
-		if sl, ok := node.(*ast.StringLiteral); ok {
-			expr, _, err = transpileStringLiteral(p, sl, true)
-			if _, ok := p.Structs[e.Type1]; !ok {
-				expr, _, err = transpileStringLiteral(p, sl, false)
+
+		var isStringLiteral bool
+		var sl *ast.StringLiteral
+
+		sl, isStringLiteral = node.(*ast.StringLiteral)
+		if !isStringLiteral {
+			if impl, ok := node.(*ast.ImplicitCastExpr); ok && len(impl.Children()) > 0 {
+				sl, isStringLiteral = impl.Children()[0].(*ast.StringLiteral)
 			}
-		} else {
-			expr, _, _, _, err = transpileToExpr(node, p, true)
 		}
-		if err != nil {
-			p.AddMessage(p.GenerateWarningMessage(err, node))
-			return nil, "", err
+
+		expr, eType, _, _, err = transpileToExpr(node, p, true)
+		p.AddMessage(p.GenerateWarningMessage(err, node))
+
+		if isStruct {
+			if fieldType, ok := structType.Fields[structType.FieldNames[fieldPos]]; ok {
+				if ft, ok := fieldType.(string); ok {
+
+					arr, arrFieldSize := types.GetArrayTypeAndSize(ft)
+					_, arrExprSize := types.GetArrayTypeAndSize(eType)
+
+					if isStringLiteral && arrFieldSize > 0 {
+						expr, eType, err = transpileStringLiteral(p, sl, true)
+					} else if arrFieldSize > 0 && arrExprSize < 0 {
+						var fixed bool
+						switch v := expr.(type) {
+						case *goast.CompositeLit:
+							if id, ok := v.Type.(*goast.Ident); ok {
+								goType, err := types.ResolveType(p, arr)
+								p.AddMessage(p.GenerateWarningMessage(err, nil))
+								id.Name = fmt.Sprintf("[%d]%s", arrFieldSize, goType)
+								fixed = true
+							}
+						case *goast.CallExpr:
+							if id, ok := v.Fun.(*goast.Ident); ok {
+								goType, err := types.ResolveType(p, arr)
+								p.AddMessage(p.GenerateWarningMessage(err, nil))
+								id.Name = fmt.Sprintf("[%d]%s", arrFieldSize, goType)
+								fixed = true
+							}
+						}
+						if !fixed {
+							err = fmt.Errorf("cannot fix slice to array for type : %T", expr)
+						}
+					}
+				}
+			}
 		}
 
+		p.AddMessage(p.GenerateWarningMessage(err, node))
+
 		resp = append(resp, expr)
 	}
 
-	var t goast.Expr
-	var cTypeString string
+	goType, err := types.ResolveType(p, e.Type1)
+	if err != nil {
+		return nil, "", err
+	}
 
 	arrayType, arraySize := types.GetArrayTypeAndSize(e.Type1)
-	if arraySize != -1 {
-		goArrayType, err := types.ResolveType(p, arrayType)
-		p.AddMessage(p.GenerateWarningMessage(err, e))
-
-		cTypeString = fmt.Sprintf("%s[%d]", arrayType, arraySize)
-
-		if hasArrayFiller {
-			t = &goast.ArrayType{
-				Elt: &goast.Ident{
-					Name: goArrayType,
-				},
-				Len: util.NewIntLit(arraySize),
-			}
-
-			// Array fillers do not work with slices.
-			// We initialize the array first, then convert to a slice.
-			// For example: (&[4]int{1,2})[:]
-			return &goast.SliceExpr{
-				X: &goast.ParenExpr{
-					X: &goast.UnaryExpr{
-						Op: token.AND,
-						X: &goast.CompositeLit{
-							Type: t,
-							Elts: resp,
-						},
-					},
-				},
-			}, cTypeString, nil
+	if arraySize > 0 {
+		for i := len(resp); i < arraySize; i++ {
+			zero, _ := zeroValue(p, arrayType)
+			resp = append(resp, zero)
 		}
+		exprType = arrayType + "[]"
 	}
 
-	goType, err := types.ResolveType(p, e.Type1)
-	if err != nil {
-		return nil, "", err
+	if len(resp) == 1 && goType == "[]byte" {
+		return resp[0], exprType, nil
 	}
 
 	return &goast.CompositeLit{
 		Type: goast.NewIdent(goType),
 		Elts: resp,
-	}, e.Type1, nil
+	}, exprType, nil
+}
+
+func zeroValue(p *program.Program, cType string) (zero goast.Expr, zeroType string) {
+	zeroType = cType
+	goType, err := types.ResolveType(p, cType)
+	p.AddMessage(p.GenerateWarningMessage(err, nil))
+
+	// for structs
+	if tt, ok := p.GetBaseTypeOfTypedef(cType); ok {
+		if _, ok := p.Structs[tt]; ok {
+			zero = goast.NewIdent(fmt.Sprintf("%s{}", goType))
+			return
+		}
+	}
+	if _, ok := p.Structs[cType]; ok {
+		zero = goast.NewIdent(fmt.Sprintf("%s{}", goType))
+		return
+	}
+
+	switch {
+	case goType == "byte":
+		zero = goast.NewIdent("'\\x00'")
+	case types.IsCPointer(cType, p):
+		zero = goast.NewIdent("nil")
+	case types.IsCArray(cType, p):
+		arr, arrFieldSize := types.GetArrayTypeAndSize(cType)
+		goType, err := types.ResolveType(p, arr)
+		p.AddMessage(p.GenerateWarningMessage(err, nil))
+		zero = goast.NewIdent(fmt.Sprintf("[%d]%s{}", arrFieldSize, goType))
+	default:
+		zero = goast.NewIdent("0")
+	}
+
+	return
 }
 
 func transpileDeclStmt(n *ast.DeclStmt, p *program.Program) (
@@ -500,6 +569,11 @@ Selector:
 	}, n.Type, preStmts, postStmts, nil
 }
 
+// transpileImplicitValueInitExpr.
+//
+// Examples:
+//
+//  |-ImplicitValueInitExpr 0x3cea488 <<invalid sloc>> 'char *'
 func transpileImplicitValueInitExpr(n *ast.ImplicitValueInitExpr, p *program.Program) (
 	expr goast.Expr, exprType string, _ []goast.Stmt, _ []goast.Stmt, err error) {
 
@@ -508,33 +582,7 @@ func transpileImplicitValueInitExpr(n *ast.ImplicitValueInitExpr, p *program.Pro
 			err = fmt.Errorf("Cannot transpileImplicitValueInitExpr. err = %v", err)
 		}
 	}()
-
-	exprType = n.Type1
-
-	var t string
-	t = n.Type1
-	t, err = types.ResolveType(p, t)
-	p.AddMessage(p.GenerateWarningMessage(err, n))
-
-	var isStruct bool
-	if _, ok := p.Structs[t]; ok {
-		isStruct = true
-	}
-	if _, ok := p.Structs["struct "+t]; ok {
-		isStruct = true
-	}
-	if isStruct {
-		expr = &goast.CompositeLit{
-			Type:   util.NewIdent(t),
-			Lbrace: 1,
-		}
-		return
-	}
-
-	expr = util.NewCallExpr(t,
-		&goast.BasicLit{
-			Kind:  token.INT,
-			Value: "0",
-		})
+	expr, exprType = zeroValue(p, n.Type1)
 	return
+
 }
diff --git a/types/cast.go b/types/cast.go
index 8904e81..370b639 100644
--- a/types/cast.go
+++ b/types/cast.go
@@ -134,19 +134,27 @@ func CastExpr(p *program.Program, expr goast.Expr, cFromType, cToType string) (
 
 	// casting
 	if fromType == "void *" && toType[len(toType)-1] == '*' &&
-		!strings.Contains(toType, "FILE") && toType[len(toType)-2] != '*' {
+		toType[len(toType)-2] != '*' {
 		toType = strings.Replace(toType, "*", " ", -1)
 		t, err := ResolveType(p, toType)
 		if err != nil {
 			return nil, err
 		}
-		return &goast.TypeAssertExpr{
-			X:      expr,
-			Lparen: 1,
-			Type: &goast.ArrayType{
-				Lbrack: 1,
-				Elt:    util.NewIdent(t),
-			}}, nil
+		if strings.Contains(toType, "FILE") {
+			return &goast.TypeAssertExpr{
+				X:      expr,
+				Lparen: 1,
+				Type:   goast.NewIdent("*noarch.File"),
+			}, nil
+		} else {
+			return &goast.TypeAssertExpr{
+				X:      expr,
+				Lparen: 1,
+				Type: &goast.ArrayType{
+					Lbrack: 1,
+					Elt:    util.NewIdent(t),
+				}}, nil
+		}
 	}
 
 	// Checking amount recursive typedef element


Test patch:
diff --git a/ast/alloc_size_attr_test.go b/ast/alloc_size_attr_test.go
index 291aa88..89e2769 100644
--- a/ast/alloc_size_attr_test.go
+++ b/ast/alloc_size_attr_test.go
@@ -21,6 +21,14 @@ func TestAllocSizeAttr(t *testing.T) {
 			B:           0,
 			ChildNodes:  []Node{},
 		},
+		`0xb8abfd90 <col:100, col:116> 2`: &AllocSizeAttr{
+			Addr:        0xb8abfd90,
+			Pos:         NewPositionFromString("col:100, col:116"),
+			IsInherited: false,
+			A:           2,
+			B:           0,
+			ChildNodes:  []Node{},
+		},
 	}
 
 	runNodeTests(t, nodes)
diff --git a/ast/enable_if_attr_test.go b/ast/enable_if_attr_test.go
new file mode 100644
index 0000000..0a9aad8
--- /dev/null
+++ b/ast/enable_if_attr_test.go
@@ -0,0 +1,19 @@
+package ast
+
+import (
+	"testing"
+)
+
+func TestEnableIfAttr(t *testing.T) {
+	nodes := map[string]Node{
+		`0xb8add300 <col:91, col:106> "<no message provided>"`: &EnableIfAttr{
+			Addr:        0xb8add300,
+			Pos:         NewPositionFromString("col:91, col:106"),
+			Message1:    "<no message provided>",
+			IsInherited: false,
+			ChildNodes:  []Node{},
+		},
+	}
+
+	runNodeTests(t, nodes)
+}
diff --git a/ast/overloadable_attr_test.go b/ast/overloadable_attr_test.go
new file mode 100644
index 0000000..90d6fcd
--- /dev/null
+++ b/ast/overloadable_attr_test.go
@@ -0,0 +1,17 @@
+package ast
+
+import (
+	"testing"
+)
+
+func TestOverloadableAttr(t *testing.T) {
+	nodes := map[string]Node{
+		`0x7fa3b88bbb38 <line:4:1, line:13:1>`: &OverloadableAttr{
+			Addr:       0x7fa3b88bbb38,
+			Pos:        NewPositionFromString("line:4:1, line:13:1"),
+			ChildNodes: []Node{},
+		},
+	}
+
+	runNodeTests(t, nodes)
+}
diff --git a/tests/init.c b/tests/init.c
new file mode 100644
index 0000000..3c455f2
--- /dev/null
+++ b/tests/init.c
@@ -0,0 +1,331 @@
+// Initialization structs, arrays, ...
+
+#include "tests.h"
+#include <stdio.h>
+
+#define START_TEST(t) \
+    diag(#t);         \
+    test_##t();
+
+void test_array_float()
+{
+    float a[] = { 2.2, 3.3, 4.4 };
+    is_eq(a[0], 2.2);
+    is_eq(a[1], 3.3);
+    is_eq(a[2], 4.4);
+}
+
+void test_array_char()
+{
+    char a[] = { 'a', 'b', 'c' };
+    is_eq(a[0], 'a');
+    is_eq(a[1], 'b');
+    is_eq(a[2], 'c');
+}
+
+void test_struct_init()
+{
+	struct s {
+		int i;
+		char c;
+	};
+
+    struct s a[] = { { 1, 'a' }, { 2, 'b' } };
+    is_eq(a[0].i, 1);
+    is_eq(a[0].c, 'a');
+    is_eq(a[1].i, 2);
+    is_eq(a[1].c, 'b');
+
+    struct s c[2][3] = { { { 1, 'a' }, { 2, 'b' }, { 3, 'c' } }, { { 4, 'd' }, { 5, 'e' }, { 6, 'f' } } };
+    is_eq(c[1][1].i, 5);
+    is_eq(c[1][1].c, 'e');
+}
+
+void test_matrix_double()
+{
+    int a[2][3] = { { 5, 6, 7 }, { 50, 60, 70 } };
+    is_eq(a[1][2], 70);
+}
+
+static char *kmap_fa[256] = {
+	[ 0 ] = "fa",
+	['`'] = "@",
+	['1'] = "abc",
+};
+void test_equals_chars()
+{
+	is_streq(kmap_fa[ 0 ], "fa" );
+	is_streq(kmap_fa['`'], "@"  );
+	is_streq(kmap_fa['1'], "abc");
+	for (int i=0;i < 256;i++) {
+			kmap_fa[i] = "Y";
+	}
+}
+
+static char *di[][2] = {
+	{"cq", ";"},
+	{"pl", "+"},
+	{"hy", "-"},
+	{"sl", "/"},
+};
+void test_di()
+{
+	is_streq(di[0][0], "cq");
+	is_streq(di[1][0], "pl");
+	is_streq(di[2][0], "hy");
+	is_streq(di[3][0], "sl");
+	is_streq(di[0][1], ";");
+	is_streq(di[1][1], "+");
+	is_streq(di[2][1], "-");
+	is_streq(di[3][1], "/");
+}
+
+
+int ec_print(char *s){
+	printf("%s\n",s);
+	return 32;
+}
+int ec_insert(char *s){
+	printf("%s\n",s);
+	return 42;
+}
+static struct excmd {
+	char *abbr;
+	char *name;
+	int (*ec)(char *s);
+} excmds[] = {
+	{"p", "print", ec_print},
+	{"a", "append", ec_insert},
+	{},
+};
+void test_ex()
+{
+	is_streq(excmds[0].abbr, "p")
+	is_streq(excmds[0].name, "print")
+	is_eq(excmds[0].ec("0"), 32);
+	
+	is_streq(excmds[1].abbr, "a")
+	is_streq(excmds[1].name, "append")
+	is_eq(excmds[1].ec("1"), 42);
+
+	is_true(excmds[2].abbr == NULL);
+	is_true(excmds[2].name == NULL);
+	is_true(excmds[2].ec   == NULL);
+}
+
+#define test_part_array_pointer(type)		\
+{											\
+	diag("test_part_array_pointer");		\
+    diag(#type);							\
+	type a0 = 1;							\
+	type a1 = 3;							\
+	type aZ = 4;							\
+	type * d[5] = { &a0 , &a1 };			\
+	is_eq(*d[0], a0);						\
+	is_eq(*d[1], a1);						\
+	is_true(d[4] == NULL);					\
+	for (int i = 0; i < 5; i++) {			\
+		d[i] = &aZ;							\
+	}										\
+	is_eq(*d[0], aZ);						\
+	is_eq(*d[1], aZ);						\
+}
+
+#define test_part_array(type)		\
+{									\
+    diag("test_part_array");		\
+	diag(#type); 					\
+	type d[5] = { 1 , 3 };			\
+	is_eq(d[0], 1);					\
+	is_eq(d[1], 3);					\
+	for (int i = 0; i < 5; i++) {	\
+		d[i] = (float) i;			\
+	}								\
+	is_eq(d[0], 0);					\
+	is_eq(d[1], 1);					\
+}
+
+void test_partly()
+{
+	// Test partly initialization of array
+	test_part_array(char            );
+	test_part_array(double          );
+	test_part_array(float           );
+	test_part_array(int             );
+	test_part_array(long double     );
+	test_part_array(long long       );
+	test_part_array(signed char     );
+	test_part_array(unsigned long   );
+
+	// Test partly initialization of array pointer
+	test_part_array_pointer(char               );
+	test_part_array_pointer(double             );
+	test_part_array_pointer(float              );
+	test_part_array_pointer(int                );
+	test_part_array_pointer(long double        );
+	test_part_array_pointer(long long          );
+	test_part_array_pointer(signed char        );
+	test_part_array_pointer(unsigned long      );
+}
+
+void test_FILE()
+{
+	FILE * F[3] = {stderr};
+	is_true(F[0] == stderr);
+	for (int i = 0; i < 3;i++) {
+		F[i] = stdout;	
+	}
+	is_true(F[1] == stdout);
+}
+
+void test_void()
+{
+	void * v[3] = {stderr};
+	is_true((FILE *)(v[0]) == stderr);
+	double r = 42;
+	for (int i = 0; i < 3;i++) {
+		v[i] = &r;	
+	}
+	is_eq(*(double *)(v[1]) , r);
+}
+
+static int xai, xaw;
+static struct option {
+	char *abbr;
+	char *name;
+	int  *vars;
+} options[] = {
+	{"ai", "autoindent", &xai},
+	{"aw", "autowrite", &xaw},
+	{},
+};
+void test_options()
+{
+	is_streq(options[0].abbr, "ai");
+	is_streq(options[0].name, "autoindent");
+	is_not_null(options[0].vars);
+
+	is_streq(options[1].abbr, "aw");
+	is_streq(options[1].name, "autowrite");
+	is_not_null(options[1].vars);
+
+	is_true(options[2].abbr == NULL);
+	is_true(options[2].name == NULL);
+	is_true(options[2].vars == NULL);
+}
+
+static struct hig{
+	char *ft;
+	int att[16];
+	char *pat;	
+	int end;	
+} higs[] = {
+	{},
+	{"c", {5}, "q"},
+	{"2", {4}, "w"},
+	{},
+};
+void test_hig()
+{
+	is_true  (higs[0].ft     == NULL);
+	// TODO : is_true  (higs[0].att[0] == NULL);
+	is_true  (higs[0].pat    == NULL);
+
+	is_streq(higs[1].ft    , "c");
+	is_eq   (higs[1].att[0],  5 );
+	is_streq(higs[1].pat   , "q");
+
+	is_streq(higs[2].ft    , "2");
+	is_eq   (higs[2].att[0],  4 );
+	is_streq(higs[2].pat   , "w");
+
+	is_true  (higs[3].ft     == NULL);
+	// TODO : is_true  (higs[3].att[0] == NULL);
+	is_true  (higs[3].pat    == NULL);
+}
+
+typedef struct hig hug;
+void test_hug()
+{
+	hug hugs[] = {
+		{"c", {5}, "q"},
+		{"2", {4}, "w"},
+	};
+	is_streq(hugs[0].ft    , "c");
+	is_eq   (hugs[0].att[0],  5 );
+	is_streq(hugs[0].pat   , "q");
+
+	is_streq(hugs[1].ft    , "2");
+	is_eq   (hugs[1].att[0],  4 );
+	is_streq(hugs[1].pat   , "w");
+}
+
+struct poz{
+	char           y[5];
+	char          *c   ;
+	double         d[2];
+	struct poz    *ppt ;
+	struct hig  parr[3];
+	hug            h[9];
+} pozes[] = {
+	{"dream","home", {1, 2}},
+	{"hold" ,"a"   , {0,42}},
+	{},
+};
+void test_poz()
+{
+	is_streq(pozes[0].y   , "dream");
+	is_streq(pozes[0].c   , "home" );
+	is_eq   (pozes[0].d[0], 1      );
+	is_eq   (pozes[0].d[1], 2      );
+	
+	is_streq(pozes[1].y   , "hold" );
+	is_streq(pozes[1].c   , "a"    );
+	is_eq   (pozes[1].d[0], 0      );
+	is_eq   (pozes[1].d[1], 42     );
+
+	is_not_null(&pozes[2]);
+}
+
+void test_ab()
+{
+	char * num[3] = {{"123"},{"987"},{"456"}};
+	is_streq(num[0], "123");
+	is_streq(num[1], "987");
+	is_streq(num[2], "456");
+}
+
+void test_vti()
+{
+    int aqq[1][1] = { { 5 } };
+	is_eq(aqq[0][0], 5);
+}
+
+int main()
+{
+    plan(147);
+
+	START_TEST(partly);
+
+	// Test partly initialization of FILE
+	START_TEST(FILE)
+
+	// Test partly initialization of void
+	START_TEST(void)
+
+    START_TEST(array_float);
+    START_TEST(array_char);
+    START_TEST(struct_init);
+    START_TEST(matrix_double);
+	START_TEST(equals_chars);
+	START_TEST(di);
+	START_TEST(options);
+	START_TEST(ex);
+	START_TEST(hig);
+	START_TEST(hug);
+	START_TEST(poz);
+	START_TEST(ab);
+	START_TEST(vti);
+	
+    done_testing();
+}
diff --git a/tests/stdlib.c b/tests/stdlib.c
index 0f47b8f..699d697 100644
--- a/tests/stdlib.c
+++ b/tests/stdlib.c
@@ -267,9 +267,27 @@ void struct_with_define()
     is_eq(a.im, 12);
 }
 
+void test_atoi_post()
+{
+	char * num[3] = {{"123"},{"987"},{"456"}};
+	char **w = &num;
+	int n;
+	n = atoi(*w);
+	is_streq(*w, "123");
+	is_eq(n,123);
+
+	n = atoi((*w)++);
+	is_streq(*w, "23");
+	is_eq(n,123);
+	
+	n = atoi((*w));
+	is_streq(*w, "23");
+	is_eq(n,23);
+}
+
 int main()
 {
-    plan(757);
+    plan(763);
 
     struct_with_define();
 
@@ -550,8 +568,13 @@ int main()
 		printf("%d %d\n", abs(h)/100, abs(h) %100);
 	}
 
+	diag("atoi_post");
+	test_atoi_post();
+
+	diag("system");
     test_system();
 
+	diag("q_sort");
     q_sort();
 
     done_testing();