Repository: Konstantin8105/c4go
Pull request #320 (2019-03-16 10:51:10)

pointer arith


Patch:
diff --git a/program/program.go b/program/program.go
index 9514494..ba73779 100644
--- a/program/program.go
+++ b/program/program.go
@@ -333,9 +333,18 @@ type nilWalker struct {
 }
 
 func (n nilWalker) Visit(node goast.Node) (w goast.Visitor) {
-	fmt.Fprintf(os.Stdout, "---------\n")
-	fmt.Fprintf(os.Stdout, "Node: %#v", node)
+	fmt.Fprintf(os.Stdout, "\n---------\n")
+	fmt.Fprintf(os.Stdout, "Node: %#v\n", node)
 	switch v := node.(type) {
+	case *goast.IndexExpr:
+		fmt.Fprintf(os.Stdout, "IndexExpr\n")
+		fmt.Fprintf(os.Stdout, "\tx     = %#v\n", v.X)
+		fmt.Fprintf(os.Stdout, "\tindex = %#v\n", v.Index)
+		if v.Index == nil {
+			goast.Print(token.NewFileSet(), v)
+			panic("")
+		}
+
 	case *goast.GenDecl:
 		fmt.Fprintf(os.Stdout, "%#v\n", v)
 		for i, s := range v.Specs {
diff --git a/program/warnings.go b/program/warnings.go
index 2aee274..61bb8a8 100644
--- a/program/warnings.go
+++ b/program/warnings.go
@@ -8,9 +8,11 @@ import (
 	"github.com/Konstantin8105/c4go/ast"
 )
 
+var WarningMessage string = "// Warning "
+
 // GenerateWarningMessage - generate warning message
 func (p *Program) GenerateWarningMessage(e error, n ast.Node) string {
-	message := "// Warning "
+	message := WarningMessage
 	if e == nil || len(e.Error()) == 0 {
 		return ""
 	}
diff --git a/transpiler/binary.go b/transpiler/binary.go
index 5d2ab21..6bcbba4 100644
--- a/transpiler/binary.go
+++ b/transpiler/binary.go
@@ -227,7 +227,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 	}
 
 	// pointer arithmetic
-	if util.IsPointer(n.Type) {
+	if types.IsPointer(n.Type, p) {
 		if operator == token.ADD || // +
 			false {
 
@@ -299,7 +299,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 		err = fmt.Errorf("cannot atomic for right part. %v", err)
 		return nil, "unknown53", nil, nil, err
 	}
-	if util.IsPointer(leftType) && util.IsPointer(rightType) && operator == token.SUB {
+	if types.IsPointer(leftType, p) && types.IsPointer(rightType, p) && operator == token.SUB {
 		p.AddImport("unsafe")
 		sizeof, err := types.SizeOf(p, types.GetBaseType(leftType))
 		if err != nil {
@@ -346,23 +346,22 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 	// To handle this, cast the shift count to a uint64.
 	if operator == token.SHL || // <<
 		operator == token.SHR || // >>
+		operator == token.SHL_ASSIGN || // <<=
+		operator == token.SHR_ASSIGN || // <<=
 		false {
 		right, err = types.CastExpr(p, right, rightType, "unsigned long long")
 		p.AddMessage(p.GenerateWarningMessage(err, n))
 		if right == nil {
 			right = util.NewNil()
 		}
-
-		return util.NewBinaryExpr(left, operator, right, "uint64", exprIsStmt),
-			leftType, preStmts, postStmts, nil
 	}
 
 	// pointer arithmetic
-	if util.IsPointer(n.Type) {
+	if types.IsPointer(n.Type, p) {
 		if operator == token.ADD || // +
 			operator == token.SUB || // -
 			false {
-			if util.IsPointer(leftType) {
+			if types.IsPointer(leftType, p) {
 				expr, eType, newPre, newPost, err =
 					pointerArithmetic(p, left, leftType, right, rightType, operator)
 			} else {
@@ -444,7 +443,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 			// | `-DeclRefExpr 'char *' lvalue Var 0x26ba988 'c' 'char *'
 			// `-ImplicitCastExpr 'char *' <LValueToRValue>
 			//   `-DeclRefExpr 'char *' lvalue Var 0x26ba8a8 'b' 'char *'
-			if util.IsCPointer(leftType) || util.IsCArray(leftType) {
+			if types.IsCPointer(leftType, p) || types.IsCArray(leftType, p) {
 				left = util.GetUintptr(left)
 				right = util.GetUintptr(right)
 				p.AddImport("unsafe")
diff --git a/transpiler/bind.go b/transpiler/bind.go
index cb1e864..e134d34 100644
--- a/transpiler/bind.go
+++ b/transpiler/bind.go
@@ -126,16 +126,28 @@ func getBindFunction(p *program.Program, d program.DefinitionFunction) (code str
 		arg = append(arg, cgoExpr)
 	}
 
-	f.Body = &goast.BlockStmt{
-		List: []goast.Stmt{
-			&goast.ReturnStmt{
-				Results: []goast.Expr{
-					util.NewCallExpr(returnResolvedType,
+	if returnResolvedType != "" {
+		f.Body = &goast.BlockStmt{
+			List: []goast.Stmt{
+				&goast.ReturnStmt{
+					Results: []goast.Expr{
+						util.NewCallExpr(returnResolvedType,
+							util.NewCallExpr(fmt.Sprintf("C.%s", d.Name), arg...),
+						),
+					},
+				},
+			},
+		}
+	} else {
+		f.Body = &goast.BlockStmt{
+			List: []goast.Stmt{
+				&goast.ReturnStmt{
+					Results: []goast.Expr{
 						util.NewCallExpr(fmt.Sprintf("C.%s", d.Name), arg...),
-					),
+					},
 				},
 			},
-		},
+		}
 	}
 
 	var buf bytes.Buffer
diff --git a/transpiler/branch.go b/transpiler/branch.go
index a972616..bd88222 100644
--- a/transpiler/branch.go
+++ b/transpiler/branch.go
@@ -255,7 +255,7 @@ func transpileForStmt(n *ast.ForStmt, p *program.Program) (
 	var transpilate bool
 	if v, ok := children[3].(*ast.UnaryOperator); ok {
 		if vv, ok := v.Children()[0].(*ast.DeclRefExpr); ok {
-			if !util.IsPointer(vv.Type) && !util.IsFunction(vv.Type) {
+			if !types.IsPointer(vv.Type, p) && !util.IsFunction(vv.Type) {
 				switch v.Operator {
 				case "++":
 					// for case:
diff --git a/transpiler/call.go b/transpiler/call.go
index da16ebc..9a6a959 100644
--- a/transpiler/call.go
+++ b/transpiler/call.go
@@ -559,7 +559,7 @@ func transpileCallExpr(n *ast.CallExpr, p *program.Program) (
 			}
 
 			if len(functionDef.ArgumentTypes) > i {
-				if !util.IsPointer(functionDef.ArgumentTypes[i]) {
+				if !types.IsPointer(functionDef.ArgumentTypes[i], p) {
 					if strings.HasPrefix(functionDef.ArgumentTypes[i], "union ") {
 						a = &goast.CallExpr{
 							Fun: &goast.SelectorExpr{
diff --git a/transpiler/cast.go b/transpiler/cast.go
index 38011a8..6397cef 100644
--- a/transpiler/cast.go
+++ b/transpiler/cast.go
@@ -44,7 +44,7 @@ func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, expr
 		// ImplicitCastExpr 'double *' <IntegralToPointer>
 		// `-ImplicitCastExpr 'long' <LValueToRValue>
 		//   `-DeclRefExpr 'long' lvalue Var 0x30e91d8 'pnt' 'long'
-		if util.IsCPointer(n.Type) {
+		if types.IsCPointer(n.Type, p) {
 			if t, ok := ast.GetTypeIfExist(n.Children()[0]); ok {
 				//
 				// ImplicitCastExpr 'char *' <IntegralToPointer>
@@ -155,9 +155,9 @@ func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, expr
 	// ImplicitCastExpr 'char *' <ArrayToPointerDecay>
 	// `-MemberExpr 'char [20]' lvalue .input_str 0x3662ba0
 	//   `-DeclRefExpr 'struct s_inp':'struct s_inp' lvalue Var 0x3662c50 's' 'struct s_inp':'struct s_inp'
-	if util.IsCPointer(n.Type) {
+	if types.IsCPointer(n.Type, p) {
 		if len(n.Children()) > 0 {
-			if memb, ok := n.Children()[0].(*ast.MemberExpr); ok && util.IsCArray(memb.Type) {
+			if memb, ok := n.Children()[0].(*ast.MemberExpr); ok && types.IsCArray(memb.Type, p) {
 				expr = &goast.SliceExpr{
 					X:      expr,
 					Lbrack: 1,
@@ -266,7 +266,7 @@ func transpileCStyleCastExpr(n *ast.CStyleCastExpr, p *program.Program, exprIsSt
 	if len(n.Children()) > 0 {
 		if types.IsCInteger(p, n.Type) {
 			if t, ok := ast.GetTypeIfExist(n.Children()[0]); ok {
-				if util.IsPointer(*t) {
+				if types.IsPointer(*t, p) {
 					// main information	: https://go101.org/article/unsafe.html
 					sizeof, err := types.SizeOf(p, types.GetBaseType(*t))
 					if err != nil {
diff --git a/transpiler/literals.go b/transpiler/literals.go
index 2e9404c..c73566c 100644
--- a/transpiler/literals.go
+++ b/transpiler/literals.go
@@ -72,7 +72,7 @@ func transpileStringLiteral(p *program.Program, n *ast.StringLiteral, arrayToArr
 		}
 	}
 	var s int
-	s, err = types.GetAmountArraySize(n.Type)
+	s, err = types.GetAmountArraySize(n.Type, p)
 	if !arrayToArray {
 		if err != nil {
 			expr = util.NewCallExpr("[]byte",
diff --git a/transpiler/operators.go b/transpiler/operators.go
index 32b7c56..68dc7ea 100644
--- a/transpiler/operators.go
+++ b/transpiler/operators.go
@@ -253,7 +253,7 @@ func pointerArithmetic(p *program.Program,
 		err = fmt.Errorf("right type is not C integer type : '%s'", rightType)
 		return
 	}
-	if !util.IsPointer(leftType) {
+	if !types.IsPointer(leftType, p) {
 		err = fmt.Errorf("left type is not a pointer : '%s'", leftType)
 		return
 	}
@@ -262,6 +262,14 @@ func pointerArithmetic(p *program.Program,
 		return
 	}
 
+	for {
+		if t, ok := p.TypedefType[leftType]; ok {
+			leftType = t
+			continue
+		}
+		break
+	}
+
 	resolvedLeftType, err := types.ResolveType(p, leftType)
 	if err != nil {
 		return
@@ -339,95 +347,33 @@ func transpileCompoundAssignOperator(
 		}
 	}()
 
-	operator := getTokenForOperator(n.Opcode)
-
-	right, rightType, newPre, newPost, err := atomicOperation(n.Children()[1], p)
-	if err != nil {
-		return nil, "", nil, nil, err
-	}
-
-	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
-
-	left, leftType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false)
-	if err != nil {
-		return nil, "", nil, nil, err
-	}
-
-	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
+	operator := n.Opcode[:len(n.Opcode)-1]
 
-	// Pointer arithmetic
-	if util.IsPointer(n.Type) &&
-		(operator == token.ADD_ASSIGN || operator == token.SUB_ASSIGN) {
-		operator = convertToWithoutAssign(operator)
-		v, vType, newPre, newPost, err := pointerArithmetic(
-			p, left, leftType, right, rightType, operator)
-		if err != nil {
-			return nil, "", nil, nil, err
-		}
-		if v == nil {
-			return nil, "", nil, nil, fmt.Errorf("Expr is nil")
-		}
-		preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
-		var name string
-		name, err = getName(p, n.Children()[0])
-		if err != nil {
-			return nil, "", nil, nil, err
-		}
-		found := false
-		if sl, ok := v.(*goast.SliceExpr); ok {
-			if ind, ok := sl.X.(*goast.IndexExpr); ok {
-				v = &goast.BinaryExpr{
-					X:  ind,
-					Op: token.ASSIGN,
-					Y:  v,
-				}
-				found = true
-			}
-		}
-		if !found {
-			v = &goast.BinaryExpr{
-				X:  goast.NewIdent(name),
-				Op: token.ASSIGN,
-				Y:  v,
-			}
-		}
-		return v, vType, preStmts, postStmts, nil
-	}
-
-	right, err = types.CastExpr(p, right, rightType, leftType)
-	if err != nil {
-		return nil, "", nil, nil, err
-	}
-	rightType = leftType
-
-	// The right hand argument of the shift left or shift right operators
-	// in Go must be unsigned integers. In C, shifting with a negative shift
-	// count is undefined behaviour (so we should be able to ignore that case).
-	// To handle this, cast the shift count to a uint64.
-	if operator == token.SHL_ASSIGN || operator == token.SHR_ASSIGN {
-		right, err = types.CastExpr(p, right, rightType, "unsigned long long")
-		p.AddMessage(p.GenerateWarningMessage(err, n))
-		if right == nil {
-			right = util.NewNil()
-		}
-	}
-
-	resolvedLeftType, err := types.ResolveType(p, leftType)
-	if err != nil {
-		p.AddMessage(p.GenerateWarningMessage(err, n))
+	if len(n.ChildNodes) != 2 {
+		err = fmt.Errorf("not enought ChildNodes: %d", len(n.ChildNodes))
+		return
 	}
 
-	if right == nil {
-		err = fmt.Errorf("Right part is nil. err = %v", err)
-		return nil, "", nil, nil, err
-	}
-	if left == nil {
-		err = fmt.Errorf("Left part is nil. err = %v", err)
-		return nil, "", nil, nil, err
+	if !types.IsCPointer(n.Type, p) && !types.IsCArray(n.Type, p) {
+		return transpileBinaryOperator(&ast.BinaryOperator{
+			Type:       n.Type,
+			Operator:   n.Opcode,
+			ChildNodes: n.ChildNodes,
+		}, p, false)
 	}
 
-	return util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt),
-		n.Type, preStmts, postStmts, nil
+	return transpileBinaryOperator(&ast.BinaryOperator{
+		Type:     n.Type,
+		Operator: "=",
+		ChildNodes: []ast.Node{
+			n.ChildNodes[0],
+			&ast.BinaryOperator{
+				Type:       n.Type,
+				Operator:   operator,
+				ChildNodes: n.ChildNodes,
+			},
+		},
+	}, p, false)
 }
 
 // getTokenForOperator returns the Go operator token for the provided C
@@ -721,7 +667,7 @@ func atomicOperation(n ast.Node, p *program.Program) (
 		if vv, ok := v.Children()[0].(*ast.UnaryOperator); ok && vv.IsPrefix && vv.Operator == "*" {
 			if vvv, ok := vv.Children()[0].(*ast.ImplicitCastExpr); ok {
 				if vvvv, ok := vvv.Children()[0].(*ast.DeclRefExpr); ok {
-					if util.IsPointer(vvvv.Type) {
+					if types.IsPointer(vvvv.Type, p) {
 						varName := vvvv.Name
 
 						var exprResolveType string
@@ -1044,7 +990,7 @@ func atomicOperation(n ast.Node, p *program.Program) (
 
 			returnValue, _, _, _, _ := transpileToExpr(decl, p, false)
 			if d, ok := decl.(*ast.DeclRefExpr); ok &&
-				util.IsPointer(d.Type) && !util.IsPointer(v.Type) {
+				types.IsPointer(d.Type, p) && !types.IsPointer(v.Type, p) {
 				returnValue = &goast.IndexExpr{
 					X: returnValue,
 					Index: &goast.BasicLit{
diff --git a/transpiler/unary.go b/transpiler/unary.go
index f48a663..00d8a88 100644
--- a/transpiler/unary.go
+++ b/transpiler/unary.go
@@ -28,78 +28,9 @@ func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operato
 		return
 	}
 
-	if util.IsPointer(n.Type) {
-		switch operator {
-		case token.INC: // ++
-			operator = token.ADD
-		case token.DEC: // --
-			operator = token.SUB
-		}
-		// remove paren - ()
-	remove_paren:
-		if p, ok := n.Children()[0].(*ast.ParenExpr); ok {
-			n.Children()[0] = p.Children()[0]
-			goto remove_paren
-		}
-
-		var left goast.Expr
-		var leftType string
-		var newPre, newPost []goast.Stmt
-		left, leftType, newPre, newPost, err = transpileToExpr(
-			n.Children()[0], p, false)
-		if err != nil {
-			return
-		}
-
-		preStmts, postStmts = combinePreAndPostStmts(
-			preStmts, postStmts, newPre, newPost)
-
-		rightType := "int"
-		right := &goast.BasicLit{
-			Kind:  token.INT,
-			Value: "1",
-		}
-
-		expr, eType, newPre, newPost, err = pointerArithmetic(
-			p, left, leftType, right, rightType, operator)
-		if err != nil {
-			return
-		}
-		if expr == nil {
-			return nil, "", nil, nil, fmt.Errorf("Expr is nil")
-		}
-
-		preStmts, postStmts = combinePreAndPostStmts(
-			preStmts, postStmts, newPre, newPost)
-
-		var name string
-		name, err = getName(p, n.Children()[0])
-		if err != nil {
-			return
-		}
-
-		found := false
-		if sl, ok := expr.(*goast.SliceExpr); ok {
-			if ind, ok := sl.X.(*goast.IndexExpr); ok {
-				expr = &goast.BinaryExpr{
-					X:  ind,
-					Op: token.ASSIGN,
-					Y:  expr,
-				}
-				found = true
-			}
-		}
-		if !found {
-			expr = &goast.BinaryExpr{
-				X:  goast.NewIdent(name),
-				Op: token.ASSIGN,
-				Y:  expr,
-			}
-		}
-		return
-	}
-
-	if v, ok := n.Children()[0].(*ast.DeclRefExpr); ok {
+	// for values
+	if v, ok := n.Children()[0].(*ast.DeclRefExpr); ok &&
+		!types.IsCArray(v.Type, p) && !types.IsCPointer(v.Type, p) {
 		switch n.Operator {
 		case "++":
 			return &goast.BinaryExpr{
@@ -116,27 +47,49 @@ func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operato
 		}
 	}
 
-	// Unfortunately we cannot use the Go increment operators because we are not
-	// providing any position information for tokens. This means that the ++/--
-	// would be placed before the expression and would be invalid in Go.
-	//
-	// Until it can be properly fixed (can we trick Go into to placing it after
-	// the expression with a magic position?) we will have to return a
-	// BinaryExpr with the same functionality.
-
-	binaryOperator := "+="
+	// for other case
+	op := "+"
 	if operator == token.DEC {
-		binaryOperator = "-="
+		op = "-"
+	}
+
+	if len(n.ChildNodes) != 1 {
+		err = fmt.Errorf("not enought ChildNodes: %d", len(n.ChildNodes))
+		return
+	}
+
+	if !types.IsCPointer(n.Type, p) && !types.IsCArray(n.Type, p) {
+
+		binaryOperator := "+="
+		if operator == token.DEC {
+			binaryOperator = "-="
+		}
+
+		return transpileBinaryOperator(&ast.BinaryOperator{
+			Type:     n.Type,
+			Operator: binaryOperator,
+			ChildNodes: []ast.Node{
+				n.ChildNodes[0],
+				&ast.IntegerLiteral{
+					Type:  "int",
+					Value: "1",
+				},
+			},
+		}, p, false)
 	}
 
 	return transpileBinaryOperator(&ast.BinaryOperator{
 		Type:     n.Type,
-		Operator: binaryOperator,
+		Operator: "=",
 		ChildNodes: []ast.Node{
-			n.Children()[0], &ast.IntegerLiteral{
-				Type:       "int",
-				Value:      "1",
-				ChildNodes: []ast.Node{},
+			n.ChildNodes[0],
+			&ast.BinaryOperator{
+				Type:     n.Type,
+				Operator: op,
+				ChildNodes: append(n.ChildNodes, &ast.IntegerLiteral{
+					Type:  "int",
+					Value: "1",
+				}),
 			},
 		},
 	}, p, false)
@@ -389,7 +342,7 @@ func pointerParts(node *ast.Node, p *program.Program) (
 		baseTypes = append(baseTypes, t)
 
 		// find
-		if util.IsCPointer(*t) || util.IsCArray(*t) {
+		if types.IsCPointer(*t, p) || types.IsCArray(*t, p) {
 			switch (*node).(type) {
 			case *ast.BinaryOperator,
 				*ast.ImplicitCastExpr,
diff --git a/types/cast.go b/types/cast.go
index 380388f..8904e81 100644
--- a/types/cast.go
+++ b/types/cast.go
@@ -263,7 +263,7 @@ func CastExpr(p *program.Program, expr goast.Expr, cFromType, cToType string) (
 		return expr, nil
 	}
 
-	if util.IsPointer(cFromType) && cToType == "bool" {
+	if IsPointer(cFromType, p) && cToType == "bool" {
 		expr = &goast.BinaryExpr{
 			X:  expr,
 			Op: token.NEQ, // !=
@@ -465,7 +465,7 @@ func CastExpr(p *program.Program, expr goast.Expr, cFromType, cToType string) (
 		return expr, nil
 	}
 
-	if IsCInteger(p, cFromType) && util.IsPointer(cToType) {
+	if IsCInteger(p, cFromType) && IsPointer(cToType, p) {
 		expr = goast.NewIdent("nil")
 		return expr, nil
 	}
diff --git a/types/resolve.go b/types/resolve.go
index 8627fcc..9919450 100644
--- a/types/resolve.go
+++ b/types/resolve.go
@@ -393,7 +393,12 @@ func IsTypedefFunction(p *program.Program, s string) bool {
 // Example :
 // In  : 'char [40]'
 // Out : 40
-func GetAmountArraySize(cType string) (size int, err error) {
+func GetAmountArraySize(cType string, p *program.Program) (size int, err error) {
+	if !IsCArray(cType, p) {
+		err = fmt.Errorf("Is not array: `%s`", cType)
+		return
+	}
+
 	reg := util.GetRegex("\\[(?P<size>\\d+)\\]")
 	match := reg.FindStringSubmatch(cType)
 
@@ -438,3 +443,54 @@ func GetBaseType(s string) string {
 	}
 	return s
 }
+
+// IsCArray - check C type is array
+func IsCArray(s string, p *program.Program) bool {
+	if len(s) == 0 {
+		return false
+	}
+	for i := len(s) - 1; i >= 0; i-- {
+		switch s[i] {
+		case ' ':
+			continue
+		case ']':
+			return true
+		default:
+			break
+		}
+	}
+	if p != nil {
+		if t, ok := p.TypedefType[s]; ok {
+			return IsCArray(t, p)
+		}
+	}
+	return false
+}
+
+// IsPointer - check type is pointer
+func IsPointer(s string, p *program.Program) bool {
+	return IsCPointer(s, p) || IsCArray(s, p)
+}
+
+//IsCPointer - check C type is pointer
+func IsCPointer(s string, p *program.Program) bool {
+	if len(s) == 0 {
+		return false
+	}
+	for i := len(s) - 1; i >= 0; i-- {
+		switch s[i] {
+		case ' ':
+			continue
+		case '*':
+			return true
+		default:
+			break
+		}
+	}
+	if p != nil {
+		if t, ok := p.TypedefType[s]; ok {
+			return IsCPointer(t, p)
+		}
+	}
+	return false
+}
diff --git a/types/sizeof.go b/types/sizeof.go
index e072744..e44a092 100644
--- a/types/sizeof.go
+++ b/types/sizeof.go
@@ -187,7 +187,7 @@ func SizeOf(p *program.Program, cType string) (size int, err error) {
 	totalArraySize := 1
 	arrayType, arraySize := GetArrayTypeAndSize(cType)
 	if arraySize <= 0 {
-		return 0, fmt.Errorf("error in array size")
+		return 0, nil
 	}
 
 	for arraySize != -1 {
diff --git a/util/goast.go b/util/goast.go
index 4ed462f..83819b5 100644
--- a/util/goast.go
+++ b/util/goast.go
@@ -312,6 +312,36 @@ func GetUintptr(expr goast.Expr) goast.Expr {
 		}
 	}
 
+	if sl, ok := expr.(*goast.SliceExpr); ok {
+		// from :
+		//
+		// 88  0: *ast.SliceExpr {
+		// 89  .  X: *ast.Ident {
+		// 91  .  .  Name: "b"
+		// 93  .  }
+		// 95  .  Low: *ast.BasicLit { ... }
+		// 99  .  }
+		// 102  }
+		//
+		// to:
+		//
+		// 0  *ast.IndexExpr {
+		// 1  .  X: *ast.Ident {
+		// 3  .  .  Name: "b"
+		// 4  .  }
+		// 6  .  Index: *ast.BasicLit { ... }
+		// 12  }
+		if sl.Low == nil {
+			sl.Low = goast.NewIdent("0")
+		}
+		PanicIfNil(sl.X, "slice is nil")
+		PanicIfNil(sl.Low, "slice low is nil")
+		expr = &goast.IndexExpr{
+			X:     sl.X,
+			Index: sl.Low,
+		}
+	}
+
 	if sl, ok := expr.(*goast.SliceExpr); ok {
 		if c, ok := sl.X.(*goast.CallExpr); ok {
 			if fin, ok := c.Fun.(*goast.Ident); ok && strings.Contains(fin.Name, "100000") {
diff --git a/util/util.go b/util/util.go
index ae65f70..db211a7 100644
--- a/util/util.go
+++ b/util/util.go
@@ -70,47 +70,6 @@ func IsFunction(s string) bool {
 	return strings.Contains(s, "(")
 }
 
-//IsCPointer - check C type is pointer
-func IsCPointer(s string) bool {
-	if len(s) == 0 {
-		return false
-	}
-	for i := len(s) - 1; i >= 0; i-- {
-		switch s[i] {
-		case ' ':
-			continue
-		case '*':
-			return true
-		default:
-			break
-		}
-	}
-	return false
-}
-
-// IsCArray - check C type is array
-func IsCArray(s string) bool {
-	if len(s) == 0 {
-		return false
-	}
-	for i := len(s) - 1; i >= 0; i-- {
-		switch s[i] {
-		case ' ':
-			continue
-		case ']':
-			return true
-		default:
-			break
-		}
-	}
-	return false
-}
-
-// IsPointer - check type is pointer
-func IsPointer(s string) bool {
-	return strings.ContainsAny(s, "*[]")
-}
-
 // IsLastArray - check type have array '[]'
 func IsLastArray(s string) bool {
 	for _, b := range s {


Test patch:
diff --git a/other_test.go b/other_test.go
index cce7a19..01bb38f 100644
--- a/other_test.go
+++ b/other_test.go
@@ -16,6 +16,8 @@ import (
 	"sync"
 	"sync/atomic"
 	"testing"
+
+	"github.com/Konstantin8105/c4go/program"
 )
 
 func getFileList(prefix, gitSource string) (fileList []string, err error) {
@@ -80,10 +82,6 @@ func TestBookSources(t *testing.T) {
 			prefix:    "Tinn",
 			gitSource: "https://github.com/glouw/tinn.git",
 		},
-		{
-			prefix:    "kilo editor",
-			gitSource: "https://github.com/antirez/kilo.git",
-		},
 		{
 			prefix:    "brainfuck",
 			gitSource: "https://github.com/kgabis/brainfuck-c.git",
@@ -661,3 +659,69 @@ func TestMultifiles(t *testing.T) {
 		}
 	}
 }
+
+func TestKiloEditor(t *testing.T) {
+
+	prefix := "kilo editor"
+	gitSource := "https://github.com/antirez/kilo.git"
+
+	fileList, err := getFileList(prefix, gitSource)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(fileList) != 1 {
+		t.Fatalf("fileList is not correct: %v", fileList)
+	}
+
+	if !strings.Contains(fileList[0], "kilo.c") {
+		t.Fatalf("filename is not correct: %v", fileList[0])
+	}
+
+	goFile := fileList[0] + ".go"
+	args := DefaultProgramArgs()
+	args.inputFiles = []string{fileList[0]}
+	args.outputFile = goFile
+	args.ast = false
+	args.verbose = false
+
+	if err := Start(args); err != nil {
+		t.Fatalf("Cannot transpile `%v`: %v", args, err)
+	}
+
+	// warning is not acceptable
+	dat, err := ioutil.ReadFile(goFile)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if bytes.Contains(dat, []byte(program.WarningMessage)) {
+		t.Fatalf("find warning message")
+	}
+
+	// calculate amount unsafe operations
+	if count := bytes.Count(dat, []byte("unsafe.Pointer")); count > 54 {
+		t.Fatalf("too much unsafe operations: %d", count)
+	} else {
+		t.Logf("amount unsafe operations: %d", count)
+	}
+	if count := bytes.Count(dat, []byte("uintptr")); count > 12 {
+		t.Fatalf("too much uintptr operations: %d", count)
+	} else {
+		t.Logf("amount uintptr operations: %d", count)
+	}
+
+	cmd := exec.Command("go", "build",
+		"-o", goFile+".app",
+		"-gcflags", "-e",
+		goFile)
+	cmdOutput := &bytes.Buffer{}
+	cmdErr := &bytes.Buffer{}
+	cmd.Stdout = cmdOutput
+	cmd.Stderr = cmdErr
+	err = cmd.Run()
+	if err != nil {
+		t.Fatalf("Go build test `%v` : err = %v\n%v",
+			goFile, err, cmdErr.String())
+	}
+}
diff --git a/tests/ap.c b/tests/ap.c
index 1024cc7..102629b 100644
--- a/tests/ap.c
+++ b/tests/ap.c
@@ -13,8 +13,17 @@ long get() {
 	return (long)(0);
 }
 
+
+double global;
+
+double * get_value()
+{
+       return &global;
+}
+
+
 int main() {
-    plan(0);
+    plan(4);
 
 	diag("value");
 	int i1 = 42; a(&i1); b(&i1, 1);
@@ -51,5 +60,23 @@ int main() {
 	diag("pointer arithmetic 6");
 	int *i11 = 1 + 0 + i5 + 5*get() + get() - (12 + 3)*get(); a(i11); b(i11,1);
 
-    done_testing();
+	diag("pointer from function");
+	global = 42;
+	double *i12 = get_value();
+	is_eq(*i12, global);
+
+	diag("pointer for some type");
+	typedef int  NUMBER;
+	typedef int* POINTER;
+	NUMBER  num;
+	POINTER pnt;
+	int num_value = 56;
+	num = num_value;
+	pnt = &num;
+	is_eq(*pnt, num_value);
+	*pnt =  123;
+	is_eq(*pnt, 123);
+	is_eq( num, 123);
+
+	done_testing();
 }
diff --git a/tests/array.c b/tests/array.c
index 86f6d61..7520afe 100644
--- a/tests/array.c
+++ b/tests/array.c
@@ -532,9 +532,39 @@ void test_string_array()
 	}
 }
 
+void test_typedef_pointer()
+{
+	typedef double * pd;
+	double v[2] = {42.,-42.};
+	{
+		diag("typedef_pointer : 1");
+		pd     p = &v[0];
+		p++;
+		is_eq(*p,v[1]);
+	}
+	{
+		diag("typedef_pointer : 2");
+		pd     p = v;
+		p+=1;
+		is_eq(*p,v[1]);
+	}
+	{
+		diag("typedef_pointer : 3");
+		pd     p = &v[1] - 1;
+		p = 0 + p + 0 + 1;
+		is_eq(*p,v[1]);
+	}
+	{
+		diag("typedef_pointer : 4");
+		pd     p = 0 + v + 1 + 0 - 1;  // v[0]
+		p = 0 + p + 0 + 1 - 0 + 1 - 1; // p = p + 1
+		is_eq(*p,v[1]);
+	}
+}
+
 int main()
 {
-    plan(180);
+    plan(184);
 
     test_parg_struct();
     START_TEST(struct_init);
@@ -559,7 +589,9 @@ int main()
     START_TEST(stringarr_init);
     START_TEST(partialarr_init);
     START_TEST(function_array);
+	START_TEST(typedef_pointer);
 
+	diag("arrayEx");
     is_eq(arrayEx[1], 2.0);
 
     diag("Array arithmetic");
diff --git a/tests/sizeof.c b/tests/sizeof.c
index 3a83f85..554e128 100644
--- a/tests/sizeof.c
+++ b/tests/sizeof.c
@@ -36,9 +36,15 @@ union MyUnion {
 short a;
 int b;
 
+struct MyNums {
+    char name[100];
+    int size;
+    int numbers[];
+};
+
 int main()
 {
-    plan(54);
+    plan(55);
 
     diag("Integer types");
     check_sizes(char, 1);
@@ -101,5 +107,8 @@ int main()
     is_eq(sizeof(f), 48);
     is_streq(f[1], "b");
 
+	diag("MyNums");
+	is_eq(sizeof(struct MyNums), 104);
+
     done_testing();
 }
diff --git a/tests/struct.c b/tests/struct.c
index c806bb8..890d3c2 100644
--- a/tests/struct.c
+++ b/tests/struct.c
@@ -598,10 +598,38 @@ void test_same_name()
 	diag("=================");
 }
 
+typedef int pointx;
+typedef struct  {
+    pointx x;
+    int y;
+} Point2;
+const Point2 p2[] = { { .y = 4, .x = 5 } };
+const Point2* getPoint(int index) {
+    return &(p2[index]);
+}
+typedef unsigned char pcre_uchar;
+typedef unsigned char pcre_uint8;
+typedef unsigned int pcre_uint32;
+typedef struct spu {
+    pcre_uchar *hvm;
+} spu;
+
+void pointer_arithm_in_struct() {
+    pcre_uchar str[] = "abcd";
+    spu s;
+    spu *ps = &s;
+    ps->hvm = &str[1];
+    is_true(ps->hvm == &str[1]);
+    ps->hvm += 2;
+    is_true(ps->hvm == &str[3]);
+
+}
+
 int main()
 {
-    plan(98);
+    plan(100);
 
+	pointer_arithm_in_struct();
     test_extern_vec();
     test_map_resize();
     struct_typ2();
diff --git a/types/resolve_test.go b/types/resolve_test.go
index 805da98..f4aa409 100644
--- a/types/resolve_test.go
+++ b/types/resolve_test.go
@@ -63,3 +63,35 @@ func TestResolveError(t *testing.T) {
 		})
 	}
 }
+
+func TestGetAmountArraySize(t *testing.T) {
+	tcs := []struct {
+		cType string
+		value int
+		e     bool
+	}{
+		{
+			cType: "char [40]",
+			value: 40,
+			e:     false,
+		},
+		{
+			cType: "char",
+			e:     true,
+		},
+		{
+			cType: "unsigned char",
+			e:     true,
+		},
+	}
+
+	for _, tc := range tcs {
+		s, err := types.GetAmountArraySize(tc.cType, nil)
+		if err != nil && tc.e {
+			continue
+		}
+		if s != tc.value {
+			t.Errorf("%d != %d", s, tc.value)
+		}
+	}
+}
diff --git a/types/sizeof_test.go b/types/sizeof_test.go
index d4f325b..fe1c61d 100644
--- a/types/sizeof_test.go
+++ b/types/sizeof_test.go
@@ -26,23 +26,24 @@ var sizeofTestCases = []sizeofTestCase{
 	{"int ***", 8, true},
 	{"char *const", 8, true},
 	{"char *const [3]", 24, true},
-	{"struct c [2]", 0, false},
+	{"struct c [2]", 0, true},
 }
 
 func TestSizeOf(t *testing.T) {
 	p := program.NewProgram()
 
 	for _, testCase := range sizeofTestCases {
-		size, err := types.SizeOf(p, testCase.cType)
-		if !((err != nil && testCase.isError == false) ||
-			(err == nil && testCase.isError == true)) {
-			t.Error(err)
-			continue
-		}
+		t.Run(testCase.cType, func(t *testing.T) {
+			size, err := types.SizeOf(p, testCase.cType)
+			if !((err != nil && testCase.isError == false) ||
+				(err == nil && testCase.isError == true)) {
+				t.Fatal(err)
+			}
 
-		if size != testCase.size {
-			t.Errorf("Expected '%s' -> '%d', got '%d'",
-				testCase.cType, testCase.size, size)
-		}
+			if size != testCase.size {
+				t.Errorf("Expected '%s' -> '%d', got '%d'",
+					testCase.cType, testCase.size, size)
+			}
+		})
 	}
 }