Repository: Konstantin8105/c4go
Pull request #432 (2019-04-30 21:46:43)

c-testsuite: tests


Patch:
diff --git a/ast/ast.go b/ast/ast.go
index c006145..0500795 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -168,10 +168,14 @@ func Parse(fullline string) (returnNode Node, err error) {
 		return parseFunctionDecl(line), nil
 	case "FullComment":
 		return parseFullComment(line), nil
+	case "FunctionNoProtoType":
+		return parseFunctionNoProtoType(line), nil
 	case "FunctionProtoType":
 		return parseFunctionProtoType(line), nil
 	case "ForStmt":
 		return parseForStmt(line), nil
+	case "GenericSelectionExpr":
+		return parseGenericSelectionExpr(line), nil
 	case "HTMLStartTagComment":
 		return parseHTMLStartTagComment(line), nil
 	case "HTMLEndTagComment":
diff --git a/ast/enum_decl.go b/ast/enum_decl.go
index 9da1dac..fec0b67 100644
--- a/ast/enum_decl.go
+++ b/ast/enum_decl.go
@@ -7,6 +7,7 @@ import (
 // EnumDecl is node represents a enum declaration.
 type EnumDecl struct {
 	Addr       Address
+	Prev       string
 	Parent     Address
 	Pos        Position
 	Position2  string
@@ -18,6 +19,7 @@ func parseEnumDecl(line string) *EnumDecl {
 	groups := groupsFromRegex(
 		//`<(?P<position>.*)>(?P<position2> .+:\d+)?(?P<name>.*)`,
 		`(?:parent (?P<parent>0x[0-9a-f]+) )?
+		(?:prev (?P<prev>0x[0-9a-f]+) )?
 		<(?P<position>.*)>
 		(?P<position2> .+:\d+)?
 		(?P<name>.*)`,
@@ -27,6 +29,7 @@ func parseEnumDecl(line string) *EnumDecl {
 	return &EnumDecl{
 		Addr:       ParseAddress(groups["address"]),
 		Parent:     ParseAddress(groups["parent"]),
+		Prev:       groups["prev"],
 		Pos:        NewPositionFromString(groups["position"]),
 		Position2:  groups["position2"],
 		Name:       strings.TrimSpace(groups["name"]),
diff --git a/ast/function_no_proto_type.go b/ast/function_no_proto_type.go
new file mode 100644
index 0000000..1a06741
--- /dev/null
+++ b/ast/function_no_proto_type.go
@@ -0,0 +1,46 @@
+package ast
+
+// FunctionNoProtoType is function proto type
+type FunctionNoProtoType struct {
+	Addr       Address
+	Type       string
+	Kind       string
+	ChildNodes []Node
+}
+
+func parseFunctionNoProtoType(line string) *FunctionNoProtoType {
+	groups := groupsFromRegex(
+		"'(?P<type>.*?)' (?P<kind>.*)",
+		line,
+	)
+
+	return &FunctionNoProtoType{
+		Addr:       ParseAddress(groups["address"]),
+		Type:       groups["type"],
+		Kind:       groups["kind"],
+		ChildNodes: []Node{},
+	}
+}
+
+// AddChild adds a new child node. Child nodes can then be accessed with the
+// Children attribute.
+func (n *FunctionNoProtoType) 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 *FunctionNoProtoType) 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 *FunctionNoProtoType) Children() []Node {
+	return n.ChildNodes
+}
+
+// Position returns the position in the original source code.
+func (n *FunctionNoProtoType) Position() Position {
+	return Position{}
+}
diff --git a/ast/generic_selection_expr.go b/ast/generic_selection_expr.go
new file mode 100644
index 0000000..a2b44d1
--- /dev/null
+++ b/ast/generic_selection_expr.go
@@ -0,0 +1,50 @@
+package ast
+
+// GenericSelectionExpr is expression.
+type GenericSelectionExpr struct {
+	Addr       Address
+	Pos        Position
+	Type       string
+	IsLvalue   bool
+	ChildNodes []Node
+}
+
+func parseGenericSelectionExpr(line string) *GenericSelectionExpr {
+	groups := groupsFromRegex(
+		`<(?P<position>.*)>
+		 '(?P<type>.*?)'
+		(?P<lvalue> lvalue)?`,
+		line,
+	)
+
+	return &GenericSelectionExpr{
+		Addr:       ParseAddress(groups["address"]),
+		Pos:        NewPositionFromString(groups["position"]),
+		Type:       groups["type"],
+		IsLvalue:   len(groups["lvalue"]) > 0,
+		ChildNodes: []Node{},
+	}
+}
+
+// AddChild adds a new child node. Child nodes can then be accessed with the
+// Children attribute.
+func (n *GenericSelectionExpr) 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 *GenericSelectionExpr) 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 *GenericSelectionExpr) Children() []Node {
+	return n.ChildNodes
+}
+
+// Position returns the position in the original source code.
+func (n *GenericSelectionExpr) Position() Position {
+	return n.Pos
+}
diff --git a/ast/position.go b/ast/position.go
index 377fc88..d9e623d 100644
--- a/ast/position.go
+++ b/ast/position.go
@@ -324,6 +324,8 @@ func setPosition(node Node, position Position) {
 		n.Pos = position
 	case *ForStmt:
 		n.Pos = position
+	case *GenericSelectionExpr:
+		n.Pos = position
 	case *GCCAsmStmt:
 		n.Pos = position
 	case *HTMLStartTagComment:
@@ -440,7 +442,7 @@ func setPosition(node Node, position Position) {
 		n.Pos = position
 	case *TypedefType, *Typedef, *TranslationUnitDecl, *RecordType, *Record,
 		*QualType, *PointerType, *ParenType, *IncompleteArrayType,
-		*FunctionProtoType, *EnumType, *Enum, *ElaboratedType,
+		*FunctionProtoType, *FunctionNoProtoType, *EnumType, *Enum, *ElaboratedType,
 		*ConstantArrayType, *BuiltinType, *ArrayFiller, *Field,
 		*DecayedType, *CXXRecord, *AttributedType:
 		// These do not have positions so they can be ignored.
diff --git a/transpiler/call.go b/transpiler/call.go
index 1c310d4..5151974 100644
--- a/transpiler/call.go
+++ b/transpiler/call.go
@@ -42,6 +42,12 @@ func getName(p *program.Program, firstChild ast.Node) (name string, err error) {
 	case *ast.DeclRefExpr:
 		return fc.Name, nil
 
+	case *ast.GenericSelectionExpr:
+		if len(fc.Children()) == 0 {
+			return undefineFunctionName, nil
+		}
+		return getName(p, fc.Children()[0])
+
 	case *ast.MemberExpr:
 		var expr goast.Expr
 		expr, _, _, _, err = transpileToExpr(fc, p, false)
@@ -83,6 +89,13 @@ func getName(p *program.Program, firstChild ast.Node) (name string, err error) {
 		if len(fc.Children()) == 0 {
 			return undefineFunctionName, nil
 		}
+		if fc.Kind == ast.CStyleCastExprNullToPointer {
+			// CallExpr 'void'
+			// `-ParenExpr 'void (*)(void)'
+			//   `-CStyleCastExpr 'void (*)(void)' <NullToPointer>
+			//     `-IntegerLiteral 'int' 0
+			return "nil", fmt.Errorf("no name for NullToPointer")
+		}
 		return getName(p, fc.Children()[0])
 
 	case *ast.ArraySubscriptExpr:
diff --git a/transpiler/cast.go b/transpiler/cast.go
index 163be1e..0db719e 100644
--- a/transpiler/cast.go
+++ b/transpiler/cast.go
@@ -34,6 +34,15 @@ func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, expr
 		return
 	}
 
+	// avoid unsigned overflow
+	// ImplicitCastExpr 0x2e649b8 <col:6, col:7> 'unsigned int' <IntegralCast>
+	// `-UnaryOperator 0x2e64998 <col:6, col:7> 'int' prefix '-'
+	if types.IsCUnsignedType(n.Type) {
+		if un, ok := n.Children()[0].(*ast.UnaryOperator); ok && un.Operator == "-" {
+			un.Type = n.Type
+		}
+	}
+
 	expr, exprType, preStmts, postStmts, err = transpileToExpr(
 		n.Children()[0], p, exprIsStmt)
 	if err != nil {
diff --git a/transpiler/switch.go b/transpiler/switch.go
index 7c14057..d848ddf 100644
--- a/transpiler/switch.go
+++ b/transpiler/switch.go
@@ -111,6 +111,14 @@ func caseSplitter(nodes ...ast.Node) (cs []ast.Node) {
 			return false
 		}
 
+		if node == (*ast.CompoundStmt)(nil) {
+			return false
+		}
+
+		if len(node.Children()) == 0 {
+			return false
+		}
+
 		switch node.(type) {
 		case *ast.CaseStmt, *ast.DefaultStmt:
 			return true
@@ -154,7 +162,8 @@ func caseSplitter(nodes ...ast.Node) (cs []ast.Node) {
 func caseMerge(nodes []ast.Node) (pre, cs []ast.Node) {
 	for i := range nodes {
 		// ignore empty *ast.CompountStmt
-		if comp, ok := nodes[i].(*ast.CompoundStmt); ok && len(comp.Children()) == 0 {
+		if comp, ok := nodes[i].(*ast.CompoundStmt); ok &&
+			(comp == (*ast.CompoundStmt)(nil) || len(comp.Children()) == 0) {
 			continue
 		}
 
@@ -222,9 +231,12 @@ func transpileSwitchStmt(n *ast.SwitchStmt, p *program.Program) (
 	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
 
 	// separation body of switch on cases
-	body, ok := n.Children()[len(n.Children())-1].(*ast.CompoundStmt)
+	var body *ast.CompoundStmt
+	var ok bool
+	body, ok = n.Children()[len(n.Children())-1].(*ast.CompoundStmt)
 	if !ok {
-		err = fmt.Errorf("body is not ast.CompoundStmt : %T", n.Children()[len(n.Children())-1])
+		body = &ast.CompoundStmt{}
+		body.AddChild(n.Children()[len(n.Children())-1])
 	}
 
 	// CompoundStmt
@@ -241,6 +253,9 @@ func transpileSwitchStmt(n *ast.SwitchStmt, p *program.Program) (
 	//       |-<<<NULL>>>
 	//       `-DefaultStmt
 	//         `- ...
+	if body == (*ast.CompoundStmt)(nil) {
+		body = &ast.CompoundStmt{}
+	}
 	parts := caseSplitter(body.Children()...)
 	pre, parts := caseMerge(parts)
 	body.ChildNodes = parts
diff --git a/transpiler/transpiler.go b/transpiler/transpiler.go
index d0bf3d7..dfd9dba 100644
--- a/transpiler/transpiler.go
+++ b/transpiler/transpiler.go
@@ -531,7 +531,8 @@ func transpileToNode(node ast.Node, p *program.Program) (
 
 	if !AddOutsideStruct {
 		if node != nil {
-			if !p.PreprocessorFile.IsUserSource(node.Position().File) {
+			if (!p.PreprocessorFile.IsUserSource(node.Position().File)) &&
+				(!strings.HasSuffix(node.Position().File, "stdint.h")) {
 				return
 			}
 		}
diff --git a/transpiler/unary.go b/transpiler/unary.go
index f837b4d..b0da56d 100644
--- a/transpiler/unary.go
+++ b/transpiler/unary.go
@@ -4,6 +4,7 @@ package transpiler
 
 import (
 	"fmt"
+	"strconv"
 	"strings"
 
 	"github.com/Konstantin8105/c4go/ast"
@@ -594,6 +595,23 @@ func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program) (
 		return transpileUnaryOperatorAmpersant(n, p)
 	}
 
+	// Example:
+	// UnaryOperator 'unsigned int' prefix '-'
+	// `-IntegerLiteral 'unsigned int' 1
+	if il, ok := n.Children()[0].(*ast.IntegerLiteral); ok && types.IsCUnsignedType(n.Type) {
+		var value float64
+		value, err = strconv.ParseFloat(il.Value, 64)
+		if err == nil && value > 0 {
+			var resolveType string
+			resolveType, err = types.ResolveType(p, n.Type)
+			if err == nil && resolveType != "" {
+				return util.ConvertToUnsigned(goast.NewIdent(fmt.Sprintf("-%s", il.Value)), resolveType),
+					n.Type, preStmts, postStmts, nil
+			}
+		}
+		err = nil
+	}
+
 	// Example:
 	// UnaryOperator 'int' prefix '-'
 	// `-ImplicitCastExpr 'int' <LValueToRValue>
@@ -604,7 +622,6 @@ func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program) (
 	if err != nil {
 		return nil, "", nil, nil, err
 	}
-
 	preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)
 
 	return util.NewUnaryExpr(e, operator), eType, preStmts, postStmts, nil
diff --git a/types/cast.go b/types/cast.go
index 462abd0..0b659c3 100644
--- a/types/cast.go
+++ b/types/cast.go
@@ -362,6 +362,7 @@ func CastExpr(p *program.Program, expr goast.Expr, cFromType, cToType string) (
 		}
 		if fromType == "bool" && toType == v {
 			expr = util.NewCallExpr("noarch.BoolToInt", expr)
+			p.AddImport("github.com/Konstantin8105/c4go/noarch")
 			return CastExpr(p, expr, "int", cToType)
 		}
 	}
diff --git a/types/resolve.go b/types/resolve.go
index 550b8f2..d6a8544 100644
--- a/types/resolve.go
+++ b/types/resolve.go
@@ -412,7 +412,7 @@ func IsTypedefFunction(p *program.Program, s string) bool {
 	if v, ok := p.TypedefType[s]; ok && util.IsFunction(v) {
 		return true
 	}
-	s = string(s[0 : len(s)-len(" *")])
+	s = GetBaseType(s)
 	if v, ok := p.TypedefType[s]; ok && util.IsFunction(v) {
 		return true
 	}
@@ -497,6 +497,10 @@ func IsCArray(s string, p *program.Program) bool {
 	return false
 }
 
+func IsCUnsignedType(s string) bool {
+	return strings.Contains(s, "unsigned ")
+}
+
 // IsPointer - check type is pointer
 func IsPointer(s string, p *program.Program) bool {
 	return IsCPointer(s, p) || IsCArray(s, p)
diff --git a/util/goast.go b/util/goast.go
index d5bced1..7c22b77 100644
--- a/util/goast.go
+++ b/util/goast.go
@@ -382,15 +382,11 @@ func NewAnonymousFunction(body, deferBody []goast.Stmt,
 // s := func() uint {
 //		var x int64
 //		x = -1
-//		if x < 0 {
-//			x += 5
-//		}
 //		return uint(x)
 //	}()
 func ConvertToUnsigned(expr goast.Expr, returnType string) goast.Expr {
 
 	varName := "c4go_temp_name"
-	// maxValue := "123123123"
 
 	if u, ok := expr.(*goast.CallExpr); ok {
 		if i, ok := u.Fun.(*goast.Ident); ok {
@@ -425,22 +421,6 @@ func ConvertToUnsigned(expr goast.Expr, returnType string) goast.Expr {
 					Tok: token.ASSIGN,
 					Rhs: []goast.Expr{expr},
 				},
-				// &goast.IfStmt{
-				// 	Cond: &goast.BinaryExpr{
-				// 		X:  goast.NewIdent(varName),
-				// 		Op: token.LSS, // <
-				// 		Y:  goast.NewIdent("0"),
-				// 	},
-				// 	Body: &goast.BlockStmt{
-				// 		List: []goast.Stmt{
-				// 			&goast.AssignStmt{
-				// 				Lhs: []goast.Expr{goast.NewIdent(varName)},
-				// 				Tok: token.ADD_ASSIGN, // +=
-				// 				Rhs: []goast.Expr{goast.NewIdent(maxValue)},
-				// 			},
-				// 		},
-				// 	},
-				// },
 				&goast.ReturnStmt{
 					Results: []goast.Expr{
 						&goast.CallExpr{


Test patch:
diff --git a/ast/enum_decl_test.go b/ast/enum_decl_test.go
index 4426edf..22f7023 100644
--- a/ast/enum_decl_test.go
+++ b/ast/enum_decl_test.go
@@ -30,6 +30,14 @@ func TestEnumDecl(t *testing.T) {
 			Name:       "EnumTwo",
 			ChildNodes: []Node{},
 		},
+		`0x2b002c0 prev 0x2affd78 <line:28:1, line:31:1> line:28:6 efoo`: &EnumDecl{
+			Addr:       0x2b002c0,
+			Prev:       "0x2affd78",
+			Pos:        NewPositionFromString("line:28:1, line:31:1"),
+			Position2:  " line:28:6",
+			Name:       "efoo",
+			ChildNodes: []Node{},
+		},
 	}
 
 	runNodeTests(t, nodes)
diff --git a/ast/function_no_proto_type_test.go b/ast/function_no_proto_type_test.go
new file mode 100644
index 0000000..8fc7f64
--- /dev/null
+++ b/ast/function_no_proto_type_test.go
@@ -0,0 +1,18 @@
+package ast
+
+import (
+	"testing"
+)
+
+func TestFunctionNoProtoType(t *testing.T) {
+	nodes := map[string]Node{
+		`0x3e48580 'struct S *()' cdecl`: &FunctionNoProtoType{
+			Addr:       0x3e48580,
+			Type:       "struct S *()",
+			Kind:       "cdecl",
+			ChildNodes: []Node{},
+		},
+	}
+
+	runNodeTests(t, nodes)
+}
diff --git a/ast/generic_selection_expr_test.go b/ast/generic_selection_expr_test.go
new file mode 100644
index 0000000..70811c2
--- /dev/null
+++ b/ast/generic_selection_expr_test.go
@@ -0,0 +1,19 @@
+package ast
+
+import (
+	"testing"
+)
+
+func TestGenericSelectionExpr(t *testing.T) {
+	nodes := map[string]Node{
+		`0x3085aa0 <line:65:17, line:66:27> 'char [5]' lvalue`: &GenericSelectionExpr{
+			Addr:       0x3085aa0,
+			Pos:        NewPositionFromString("line:65:17, line:66:27"),
+			Type:       "char [5]",
+			IsLvalue:   true,
+			ChildNodes: []Node{},
+		},
+	}
+
+	runNodeTests(t, nodes)
+}
diff --git a/other_test.go b/other_test.go
index db18629..8bb5c1e 100644
--- a/other_test.go
+++ b/other_test.go
@@ -87,6 +87,11 @@ func TestBookSources(t *testing.T) {
 		// 	prefix:    "tiny-web-server",
 		// 	gitSource: "https://github.com/shenfeng/tiny-web-server.git",
 		// },
+		{
+			prefix:         "c-testsuite",
+			gitSource:      "https://github.com/c-testsuite/c-testsuite.git",
+			ignoreFileList: []string{},
+		},
 		{
 			prefix:    "VasielBook",
 			gitSource: "https://github.com/olegbukatchuk/book-c-the-examples-and-tasks.git",
@@ -112,14 +117,14 @@ func TestBookSources(t *testing.T) {
 				"4-10.c",
 			},
 		},
-		{
-			prefix:    "KochanBook",
-			gitSource: "https://github.com/eugenetriguba/programming-in-c.git",
-			ignoreFileList: []string{
-				"5.9d.c",
-				"5.9c.c",
-			},
-		},
+		//{
+		//	prefix:    "KochanBook",
+		//	gitSource: "https://github.com/eugenetriguba/programming-in-c.git",
+		//	ignoreFileList: []string{
+		//		"5.9d.c",
+		//		"5.9c.c",
+		//	},
+		//},
 		{
 			prefix:    "DeitelBook",
 			gitSource: "https://github.com/Emmetttt/C-Deitel-Book.git",
diff --git a/tests/code_quality/if.go.expected b/tests/code_quality/if.go.expected
index 696f255..5317a28 100644
--- a/tests/code_quality/if.go.expected
+++ b/tests/code_quality/if.go.expected
@@ -7,6 +7,8 @@
 
 package code_quality
 
+import "github.com/Konstantin8105/c4go/noarch"
+
 // if_1 - transpiled function from  C4GO/tests/code_quality/if.c:1
 func if_1() {
 	var a int32 = 5
diff --git a/tests/operators.c b/tests/operators.c
index eac86e3..94dd7be 100644
--- a/tests/operators.c
+++ b/tests/operators.c
@@ -77,7 +77,7 @@ struct UUU000 {
 
 int main()
 {
-    plan(161);
+    plan(166);
 
     is_eq(valGlobInt, 42);
     is_eq(valGlobDouble, 45);
@@ -699,6 +699,20 @@ int main()
         (void)pos;
         (void)ptr;
     }
+	{
+		diag("negative unsigned");
+		unsigned ux;
+		ux = 1;
+		is_eq(ux,1);
+		ux = -1;
+		is_eq(ux,4294967295);
+		ux = -1l;
+		is_eq(ux,4294967295);
+		ux = -1u;
+		is_eq(ux,4294967295);
+		ux = -1ll;
+		is_eq(ux,4294967295);
+	}
 	diag("simplificator");
 	{
 		char * s = "words";
diff --git a/tests/switch.c b/tests/switch.c
index 299422e..a721cc2 100644
--- a/tests/switch.c
+++ b/tests/switch.c
@@ -383,7 +383,7 @@ int case_inside_block(int a)
 
 int main()
 {
-    plan(36);
+    plan(37);
 
     switch_char();
     switch_bool();
@@ -415,5 +415,14 @@ int main()
     is_eq(case_inside_block(4), 4);
     is_eq(case_inside_block(5), 5);
 
+	diag("without parens");
+	{
+		int x = 0;
+		switch (x) 
+			case 0:
+				pass("ok");
+		(void)(x);
+	}
+
     done_testing();
 }