Repository: Konstantin8105/c4go
Pull request #278 (2019-02-23 12:29:03)

transpileImplicitCast: add cast from type to pointer of type

codecov[bot]: # [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/278?src=pr&el=h1) Report
> Merging [#278](https://codecov.io/gh/Konstantin8105/c4go/pull/278?src=pr&el=desc) into [master](https://codecov.io/gh/Konstantin8105/c4go/commit/71926d0ab510c6e2c4feebca2e6c398d630c6a04?src=pr&el=desc) will **increase** coverage by `0.08%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/Konstantin8105/c4go/pull/278/graphs/tree.svg?width=650&token=esH2rHXlZ2&height=150&src=pr)](https://codecov.io/gh/Konstantin8105/c4go/pull/278?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #278      +/-   ##
==========================================
+ Coverage   86.78%   86.86%   +0.08%     
==========================================
  Files         180      180              
  Lines        9789     9812      +23     
==========================================
+ Hits         8495     8523      +28     
+ Misses        894      890       -4     
+ Partials      400      399       -1
```


| [Impacted Files](https://codecov.io/gh/Konstantin8105/c4go/pull/278?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [transpiler/binary.go](https://codecov.io/gh/Konstantin8105/c4go/pull/278/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9iaW5hcnkuZ28=) | `71.32% <100%> (+0.42%)` | :arrow_up: |
| [transpiler/cast.go](https://codecov.io/gh/Konstantin8105/c4go/pull/278/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9jYXN0Lmdv) | `74.64% <100%> (+3.11%)` | :arrow_up: |
| [util/goast.go](https://codecov.io/gh/Konstantin8105/c4go/pull/278/diff?src=pr&el=tree#diff-dXRpbC9nb2FzdC5nbw==) | `92.17% <100%> (+0.5%)` | :arrow_up: |
| [transpiler/operators.go](https://codecov.io/gh/Konstantin8105/c4go/pull/278/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9vcGVyYXRvcnMuZ28=) | `79.52% <0%> (+0.31%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/278?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/278?src=pr&el=footer). Last update [71926d0...0a24343](https://codecov.io/gh/Konstantin8105/c4go/pull/278?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/transpiler/binary.go b/transpiler/binary.go
index 64fef37..ffc2057 100644
--- a/transpiler/binary.go
+++ b/transpiler/binary.go
@@ -280,7 +280,9 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 	// 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 || operator == token.SHR {
+	if operator == token.SHL || // <<
+		operator == token.SHR || // >>
+		false {
 		right, err = types.CastExpr(p, right, rightType, "unsigned long long")
 		p.AddMessage(p.GenerateWarningMessage(err, n))
 		if right == nil {
@@ -293,7 +295,9 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 
 	// pointer arithmetic
 	if types.IsPointer(n.Type) {
-		if operator == token.ADD || operator == token.SUB {
+		if operator == token.ADD || // +
+			operator == token.SUB || // -
+			false {
 			if types.IsPointer(leftType) {
 				expr, eType, newPre, newPost, err =
 					pointerArithmetic(p, left, leftType, right, rightType, operator)
@@ -323,7 +327,15 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 		operator == token.SUB || // -
 		operator == token.MUL || // *
 		operator == token.QUO || // /
-		operator == token.REM { // %
+		operator == token.REM || // %
+		operator == token.LEQ || // <=
+		operator == token.GEQ || // >=
+		operator == token.ADD_ASSIGN || // +=
+		operator == token.SUB_ASSIGN || // -=
+		operator == token.MUL_ASSIGN || // *=
+		operator == token.QUO_ASSIGN || // /=
+		operator == token.REM_ASSIGN || // %=
+		false {
 
 		if rightType == types.NullPointer && leftType == types.NullPointer {
 			// example C code :
@@ -338,11 +350,13 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 			// side. This is a bit crude because we should make a better
 			// decision of which type to cast to instead of only using the type
 			// of the left side.
+
 			if operator == token.ADD || // +
 				operator == token.SUB || // -
 				operator == token.MUL || // *
 				operator == token.QUO || // /
-				operator == token.REM { // %
+				operator == token.REM || // %
+				false {
 
 				if rightType == "bool" {
 					right, err = types.CastExpr(p, right, rightType, "int")
@@ -358,10 +372,23 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
 			right, err = types.CastExpr(p, right, rightType, leftType)
 			rightType = leftType
 			p.AddMessage(p.GenerateWarningMessage(err, n))
+
+			// compare pointers
+			//
+			// BinaryOperator 'int' '<'
+			// |-ImplicitCastExpr 'char *' <LValueToRValue>
+			// | `-DeclRefExpr 'char *' lvalue Var 0x26ba988 'c' 'char *'
+			// `-ImplicitCastExpr 'char *' <LValueToRValue>
+			//   `-DeclRefExpr 'char *' lvalue Var 0x26ba8a8 'b' 'char *'
+			if types.IsCPointer(leftType) {
+				left = util.GetUintptr(left)
+				right = util.GetUintptr(right)
+				p.AddImport("unsafe")
+			}
 		}
 	}
 
-	if operator == token.ASSIGN {
+	if operator == token.ASSIGN { // =
 		// Memory allocation is translated into the Go-style.
 		allocSize := getAllocationSizeNode(p, n.Children()[1])
 
diff --git a/transpiler/cast.go b/transpiler/cast.go
index 7f3f562..fdbc9db 100644
--- a/transpiler/cast.go
+++ b/transpiler/cast.go
@@ -74,6 +74,43 @@ func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, expr
 						fmt.Errorf("used unsafe convert from integer to pointer"), n)
 					exprType = n.Type
 					return
+				} else {
+					//
+					// ImplicitCastExpr 'char *' <IntegralToPointer>
+					// `-ImplicitCastExpr 'char' <LValueToRValue>
+					//   `-ArraySubscriptExpr 'char' lvalue
+					//     |-ImplicitCastExpr 'char *' <LValueToRValue>
+					//     | `-DeclRefExpr 'char *' lvalue Var 0x413c8a8 'b' 'char *'
+					//     `-IntegerLiteral 'int' 3
+					//
+					// n.Type = 'char *'
+					// *t     = 'char'
+					//
+
+					if ind, ok := expr.(*goast.IndexExpr); ok {
+						// from :
+						//
+						// 0  *ast.IndexExpr {
+						// 1  .  X: *ast.Ident {
+						// 3  .  .  Name: "b"
+						// 4  .  }
+						// 6  .  Index: *ast.BasicLit { ... }
+						// 12  }
+						//
+						// to:
+						//
+						// 88  0: *ast.SliceExpr {
+						// 89  .  X: *ast.Ident {
+						// 91  .  .  Name: "b"
+						// 93  .  }
+						// 95  .  Low: *ast.BasicLit { ... }
+						// 99  .  }
+						// 102  }
+						expr = &goast.SliceExpr{
+							X:   ind.X,
+							Low: ind.Index,
+						}
+					}
 				}
 			}
 		}
diff --git a/util/goast.go b/util/goast.go
index 142b1ca..583c53a 100644
--- a/util/goast.go
+++ b/util/goast.go
@@ -302,6 +302,24 @@ func ConvertFunctionNameFromCtoGo(name string) string {
 	return name
 }
 
+// GetUintptr - return uintptr. Example : uintptr(unsafe.Pointer(&expr))
+func GetUintptr(expr goast.Expr) goast.Expr {
+	return &goast.CallExpr{
+		Fun: goast.NewIdent("uintptr"),
+		Args: []goast.Expr{
+			&goast.CallExpr{
+				Fun: goast.NewIdent("unsafe.Pointer"),
+				Args: []goast.Expr{
+					&goast.UnaryExpr{
+						Op: token.AND,
+						X:  expr,
+					},
+				},
+			},
+		},
+	}
+}
+
 // GetUintptrForSlice - return uintptr for slice
 // Example : uint64(uintptr(unsafe.Pointer((*(**int)(unsafe.Pointer(& ...slice... )))))))
 func GetUintptrForSlice(expr goast.Expr) (goast.Expr, string) {


Test patch:
diff --git a/tests/operators.c b/tests/operators.c
index 824fd7e..f009832 100644
--- a/tests/operators.c
+++ b/tests/operators.c
@@ -59,7 +59,7 @@ int reteg(int a)
 
 int main()
 {
-    plan(113);
+    plan(114);
 
     int i = 10;
     signed char j = 1;
@@ -485,6 +485,14 @@ int main()
 			is_eq(addr,1);
 		}
 	}
+	diag("compare char pointer");
+	{
+		char *b = "happy new code";
+		char *c = b[3];
+		if (c < b) {
+			pass("ok");
+		}
+	}
 
     done_testing();
 }