Repository: Konstantin8105/c4go
Pull request #307 (2019-03-07 21:35:13)

ast: avoid go keywords in C code

codecov[bot]: # [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/307?src=pr&el=h1) Report
> Merging [#307](https://codecov.io/gh/Konstantin8105/c4go/pull/307?src=pr&el=desc) into [master](https://codecov.io/gh/Konstantin8105/c4go/commit/cc9b771fd890ee973d88ad7a7fe8a84c9e2f76f8?src=pr&el=desc) will **decrease** coverage by `0.04%`.
> The diff coverage is `86.66%`.

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

```diff
@@            Coverage Diff             @@
##           master     #307      +/-   ##
==========================================
- Coverage   86.99%   86.94%   -0.05%     
==========================================
  Files         184      184              
  Lines       10357    10344      -13     
==========================================
- Hits         9010     8994      -16     
- Misses        933      934       +1     
- Partials      414      416       +2
```


| [Impacted Files](https://codecov.io/gh/Konstantin8105/c4go/pull/307?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [ast/call\_expr.go](https://codecov.io/gh/Konstantin8105/c4go/pull/307/diff?src=pr&el=tree#diff-YXN0L2NhbGxfZXhwci5nbw==) | `100% <100%> (ø)` | :arrow_up: |
| [ast/ast.go](https://codecov.io/gh/Konstantin8105/c4go/pull/307/diff?src=pr&el=tree#diff-YXN0L2FzdC5nbw==) | `98.93% <84.61%> (-0.39%)` | :arrow_down: |
| [util/goast.go](https://codecov.io/gh/Konstantin8105/c4go/pull/307/diff?src=pr&el=tree#diff-dXRpbC9nb2FzdC5nbw==) | `92.64% <0%> (-0.74%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/307?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/307?src=pr&el=footer). Last update [cc9b771...78f5431](https://codecov.io/gh/Konstantin8105/c4go/pull/307?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/ast/ast.go b/ast/ast.go
index 40245e5..749c504 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -3,6 +3,7 @@ package ast
 
 import (
 	"fmt"
+	"reflect"
 	"strconv"
 	"strings"
 
@@ -326,34 +327,22 @@ func groupsFromRegex(rx, line string) map[string]string {
 
 // GetTypeIfExist return string inside field Type of struct
 func GetTypeIfExist(node Node) (Type *string, ok bool) {
-	switch v := node.(type) {
-	case *IntegerLiteral:
-		return &v.Type, true
-	case *DeclRefExpr:
-		return &v.Type2, true
-	case *ArraySubscriptExpr:
-		return &v.Type, true
-	case *UnaryOperator:
-		return &v.Type, true
-	case *ParenExpr:
-		return &v.Type, true
-	case *BinaryOperator:
-		return &v.Type, true
-	case *ImplicitCastExpr:
-		return &v.Type, true
-	case *CStyleCastExpr:
-		return &v.Type, true
-	case *VAArgExpr:
-		return &v.Type, true
-	case *MemberExpr:
-		return &v.Type, true
-	case *CallExpr:
-		return &v.Type, true
-	case *CharacterLiteral:
-		return &v.Type, true
-	case *StringLiteral:
-		return &v.Type, true
+	for _, typ := range []string{"Type", "Type1", "Type2"} {
+		s := reflect.ValueOf(node).Elem()
+		typeOfT := s.Type()
+		for i := 0; i < s.NumField(); i++ {
+			f := s.Field(i)
+			name := typeOfT.Field(i).Name
+			if typ != name {
+				continue
+			}
+			_, ok := f.Interface().(string)
+			if !ok {
+				continue
+			}
+			str := f.Addr().Interface().(*string)
+			return str, true
+		}
 	}
-
 	return nil, false
 }
diff --git a/ast/call_expr.go b/ast/call_expr.go
index c71d684..12f9381 100644
--- a/ast/call_expr.go
+++ b/ast/call_expr.go
@@ -5,12 +5,13 @@ type CallExpr struct {
 	Addr       Address
 	Pos        Position
 	Type       string
+	Type2      string
 	ChildNodes []Node
 }
 
 func parseCallExpr(line string) *CallExpr {
 	groups := groupsFromRegex(
-		"<(?P<position>.*)> '(?P<type>.*?)'",
+		"<(?P<position>.*)> '(?P<type>.*?)'(:'(?P<type2>.*?)')?",
 		line,
 	)
 
@@ -18,6 +19,7 @@ func parseCallExpr(line string) *CallExpr {
 		Addr:       ParseAddress(groups["address"]),
 		Pos:        NewPositionFromString(groups["position"]),
 		Type:       groups["type"],
+		Type2:      groups["type2"],
 		ChildNodes: []Node{},
 	}
 }
diff --git a/main.go b/main.go
index 3e0e5a8..a091ea5 100644
--- a/main.go
+++ b/main.go
@@ -20,6 +20,7 @@ import (
 	"os/exec"
 	"path"
 	"path/filepath"
+	"reflect"
 	"runtime"
 	"runtime/pprof"
 	"strings"
@@ -206,6 +207,111 @@ func buildTree(nodes []treeNode, depth int) []ast.Node {
 	return results
 }
 
+// Avoid Go keywords
+var goKeywords = [...]string{
+	// keywords
+	"break", "default", "func", "interface", "select", "case", "defer",
+	"go", "map", "chan", "else", "goto", "package", "switch",
+	"fallthrough", "if", "range", "type", "continue", "for",
+	"import", "return", "var", "init",
+	// "struct",
+	// "_",
+	// "const",
+	// go packages
+	"fmt", "os", "math", "testing", "unsafe", "ioutil",
+	// types
+	"string",
+	"bool", "true", "false",
+	"int8", "uint8", "byte",
+	"int16", "uint16",
+	"int32", "rune", "uint32",
+	"int64", "uint64", // int
+	"uint", "uintptr",
+	"float32", "float64",
+	"complex64", "complex128",
+}
+var letters string = "_qwertyuiopasdfghjklzxcvbnm1234567890><"
+
+func isLetter(b byte) bool {
+	for i := range letters {
+		if letters[i] == b {
+			return true
+		}
+	}
+	return false
+}
+
+func avoidGoKeywords(tree []ast.Node) {
+	if tree == nil {
+		return
+	}
+	for i := range tree {
+		if tree[i] == nil {
+			continue
+		}
+
+		// going depper
+		avoidGoKeywords(tree[i].Children())
+
+		// modify ast node : tree[i]
+		s := reflect.ValueOf(tree[i]).Elem()
+		typeOfT := s.Type()
+		for p := 0; p < s.NumField(); p++ {
+			f := s.Field(p)
+			name := typeOfT.Field(p).Name
+			if strings.Contains(name, "Value") {
+				continue
+			}
+			_, ok := f.Interface().(string)
+			if !ok {
+				continue
+			}
+			str := f.Addr().Interface().(*string)
+
+			// avoid problem with GOPATH and `go` keyword
+			*str = strings.Replace(*str, os.Getenv("GOPATH"), "GOPATH", -1)
+
+			for _, gk := range goKeywords {
+				// example *st :
+				// from:
+				// "bool (int, bool)"
+				// to:
+				// "bool_ (int, bool_)"
+				// but for:
+				// "abool" - no changes
+				if !strings.Contains(*str, gk) {
+					continue
+				}
+				// possible changes
+				index := 0
+				iter := 0 // limit of iteration
+				for ; iter < 100; iter++ {
+					indexs := strings.Index((*str)[index:], gk)
+					if indexs < 0 {
+						break
+					}
+					index += indexs
+					// change string
+					change := true
+					if pos := index - 1; pos >= 0 && isLetter((*str)[pos]) {
+						change = false
+					}
+					if pos := index + len(gk); pos < len(*str) && isLetter((*str)[pos]) {
+						change = false
+					}
+					if change {
+						y := index + len(gk)
+						st := (*str)[:y]
+						fi := (*str)[y:]
+						*str = st + "_" + fi
+					}
+					index += len(gk)
+				}
+			}
+		}
+	}
+}
+
 // Start begins transpiling an input file.
 func Start(args ProgramArgs) (err error) {
 	lines, filePP, err := generateAstLines(args)
@@ -337,6 +443,12 @@ func generateGoCode(args ProgramArgs, lines []string, filePP preprocessor.FilePP
 		p.AddMessage(p.GenerateWarningMessage(errors.New(message), fErr.Node))
 	}
 
+	// avoid Go keywords
+	if args.verbose {
+		fmt.Fprintln(os.Stdout, "Modify nodes for avoid Go keywords...")
+	}
+	avoidGoKeywords(tree)
+
 	outputFilePath := args.outputFile
 
 	if outputFilePath == "" {


Test patch:
diff --git a/ast/call_expr_test.go b/ast/call_expr_test.go
index b8aeae1..7bad014 100644
--- a/ast/call_expr_test.go
+++ b/ast/call_expr_test.go
@@ -18,6 +18,13 @@ func TestCallExpr(t *testing.T) {
 			Type:       "int",
 			ChildNodes: []Node{},
 		},
+		`0x7f9bf3035c20 <line:7:4, col:64> 'intr':'enum rrr'`: &CallExpr{
+			Addr:       0x7f9bf3035c20,
+			Pos:        NewPositionFromString("line:7:4, col:64"),
+			Type:       "intr",
+			Type2:      "enum rrr",
+			ChildNodes: []Node{},
+		},
 	}
 
 	runNodeTests(t, nodes)
diff --git a/tests/enum.c b/tests/enum.c
index 2cecd39..7cf2033 100644
--- a/tests/enum.c
+++ b/tests/enum.c
@@ -145,10 +145,17 @@ enum {
     Lookup = 'l'
 };
 
+enum Bool { false = 0, true = 1 };
+typedef enum Bool bool;
+bool Bool_test()
+{
+	return true;
+}
+
 // main function
 int main()
 {
-    plan(44);
+    plan(48);
 
     is_eq(MBchar, 'U');
 
@@ -217,5 +224,17 @@ int main()
     is_eq(sizeof(JUMP), sizeof(int));
     is_eq(sizeof(Jan), sizeof(int));
 
+	diag("Bool");
+	is_eq(true,1);
+	is_eq(false,0);
+	is_true(Bool_test() == true);
+	bool isglobal = true;
+	if (isglobal ) {
+		pass("ok");
+	}
+	if (! isglobal ) {
+		fail("ok");
+	}
+
     done_testing();
 }