Repository: Konstantin8105/c4go
Pull request #404 (2019-04-12 14:07:04)

kilo editor: fix


Patch:
diff --git a/ast/ast.go b/ast/ast.go
index a8a6588..c006145 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -78,6 +78,8 @@ func Parse(fullline string) (returnNode Node, err error) {
 		return parseAttributedType(line), nil
 	case "AvailabilityAttr":
 		return parseAvailabilityAttr(line), nil
+	case "BinaryConditionalOperator":
+		return parseBinaryConditionalOperator(line), nil
 	case "BinaryOperator":
 		return parseBinaryOperator(line), nil
 	case "BlockCommandComment":
@@ -218,6 +220,8 @@ func Parse(fullline string) (returnNode Node, err error) {
 		return parseNotTailCalledAttr(line), nil
 	case "OffsetOfExpr":
 		return parseOffsetOfExpr(line), nil
+	case "OpaqueValueExpr":
+		return parseOpaqueValueExpr(line), nil
 	case "OverloadableAttr":
 		return parseOverloadableAttr(line), nil
 	case "PackedAttr":
diff --git a/ast/binary_conditional_operator.go b/ast/binary_conditional_operator.go
new file mode 100644
index 0000000..f6c17bc
--- /dev/null
+++ b/ast/binary_conditional_operator.go
@@ -0,0 +1,47 @@
+package ast
+
+// BinaryConditionalOperator is type of binary operator
+type BinaryConditionalOperator struct {
+	Addr       Address
+	Pos        Position
+	Type       string
+	ChildNodes []Node
+}
+
+func parseBinaryConditionalOperator(line string) *BinaryConditionalOperator {
+	groups := groupsFromRegex(
+		`<(?P<position>.*)>
+		 '(?P<type1>.*?)'`,
+		line,
+	)
+
+	return &BinaryConditionalOperator{
+		Addr:       ParseAddress(groups["address"]),
+		Pos:        NewPositionFromString(groups["position"]),
+		Type:       groups["type1"],
+		ChildNodes: []Node{},
+	}
+}
+
+// AddChild adds a new child node. Child nodes can then be accessed with the
+// Children attribute.
+func (n *BinaryConditionalOperator) 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 *BinaryConditionalOperator) 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 *BinaryConditionalOperator) Children() []Node {
+	return n.ChildNodes
+}
+
+// Position returns the position in the original source code.
+func (n *BinaryConditionalOperator) Position() Position {
+	return n.Pos
+}
diff --git a/ast/opaque_value_expr.go b/ast/opaque_value_expr.go
new file mode 100644
index 0000000..462fd46
--- /dev/null
+++ b/ast/opaque_value_expr.go
@@ -0,0 +1,46 @@
+package ast
+
+// OpaqueValueExpr is expression.
+type OpaqueValueExpr struct {
+	Addr       Address
+	Pos        Position
+	Type       string
+	ChildNodes []Node
+}
+
+func parseOpaqueValueExpr(line string) *OpaqueValueExpr {
+	groups := groupsFromRegex(
+		"<(?P<position>.*)> '(?P<type>.*)'",
+		line,
+	)
+
+	return &OpaqueValueExpr{
+		Addr:       ParseAddress(groups["address"]),
+		Pos:        NewPositionFromString(groups["position"]),
+		Type:       groups["type"],
+		ChildNodes: []Node{},
+	}
+}
+
+// AddChild adds a new child node. Child nodes can then be accessed with the
+// Children attribute.
+func (n *OpaqueValueExpr) 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 *OpaqueValueExpr) 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 *OpaqueValueExpr) Children() []Node {
+	return n.ChildNodes
+}
+
+// Position returns the position in the original source code.
+func (n *OpaqueValueExpr) Position() Position {
+	return n.Pos
+}
diff --git a/ast/position.go b/ast/position.go
index 8f49e19..377fc88 100644
--- a/ast/position.go
+++ b/ast/position.go
@@ -248,6 +248,8 @@ func setPosition(node Node, position Position) {
 		n.Pos = position
 	case *AvailabilityAttr:
 		n.Pos = position
+	case *BinaryConditionalOperator:
+		n.Pos = position
 	case *BinaryOperator:
 		n.Pos = position
 	case *BlockCommandComment:
@@ -368,6 +370,8 @@ func setPosition(node Node, position Position) {
 		n.Pos = position
 	case *OffsetOfExpr:
 		n.Pos = position
+	case *OpaqueValueExpr:
+		n.Pos = position
 	case *OverloadableAttr:
 		n.Pos = position
 	case *PackedAttr:
diff --git a/noarch/stdio.go b/noarch/stdio.go
index b73a39c..b1d3098 100644
--- a/noarch/stdio.go
+++ b/noarch/stdio.go
@@ -810,7 +810,11 @@ func Vsnprintf(buffer []byte, n int32, format []byte, varList ...interface{}) in
 	for i := range []byte(result) {
 		buffer[i] = result[i]
 	}
-	buffer[len(result)] = '\x00'
+	if len(buffer) <= len(result) {
+		buffer = append(buffer, '\x00')
+	} else {
+		buffer[len(result)] = '\x00'
+	}
 
 	n = int32(len(result))
 	return n
diff --git a/noarch/string.go b/noarch/string.go
index 0998d65..7e4dd7d 100644
--- a/noarch/string.go
+++ b/noarch/string.go
@@ -151,6 +151,9 @@ func Memmove(ptr, src interface{}, num uint32) interface{} {
 	if p, ok := ptr.([]byte); ok {
 		if s, ok := src.([]byte); ok {
 			for i := int(num); i >= 0; i-- {
+				if s[i] == '\x00' {
+					break
+				}
 				p[i] = s[i]
 			}
 			return s
diff --git a/noarch/unistd.go b/noarch/unistd.go
index 5fc852a..7f22907 100644
--- a/noarch/unistd.go
+++ b/noarch/unistd.go
@@ -2,10 +2,12 @@ package noarch
 
 import (
 	"fmt"
+	"io"
 	"os"
 
-	"golang.org/x/sys/unix"
 	"syscall"
+
+	"golang.org/x/sys/unix"
 )
 
 func Isatty(fd int32) int32 {
@@ -38,14 +40,30 @@ func Pipe(p []int32) int32 {
 }
 
 func Read(fd int32, p []byte, num uint) SsizeT {
-	n, err := syscall.Read(int(fd), p)
-	if err != nil {
+	if num == 0 {
+		return 0
+	}
+	p = p[:num]
+	var n int
+	var err error
+	switch fd {
+	case 0:
+		n, err = os.Stdin.Read(p)
+	case 1:
+		n, err = os.Stdout.Read(p)
+	case 2:
+		n, err = os.Stderr.Read(p)
+	default:
+		n, err = syscall.Read(int(fd), p)
+	}
+	if err != nil && err != io.EOF {
 		return SsizeT(-1)
 	}
 	return SsizeT(n)
 }
 
 func Write(fd int32, p []byte, num uint) SsizeT {
+	p = p[:num]
 	n, err := syscall.Write(int(fd), p)
 	if err != nil {
 		return SsizeT(-1)
diff --git a/program/program.go b/program/program.go
index 4e90095..a0770ff 100644
--- a/program/program.go
+++ b/program/program.go
@@ -110,6 +110,8 @@ type Program struct {
 
 	// IsHaveVaList
 	IsHaveVaList bool
+
+	DoNotAddComments bool
 }
 
 type commentPos struct {
@@ -204,6 +206,9 @@ func (p *Program) GetMessageComments() (_ *goast.CommentGroup) {
 
 // GetComments - return comments
 func (p *Program) GetComments(n ast.Position) (out []*goast.Comment) {
+	if p.DoNotAddComments {
+		return
+	}
 	beginLine := p.commentLine[n.File]
 	if n.Line < beginLine.line {
 		return
diff --git a/scripts/kilo.sh b/scripts/kilo.sh
index 7c0b90c..cfb63cd 100755
--- a/scripts/kilo.sh
+++ b/scripts/kilo.sh
@@ -19,6 +19,16 @@ mkdir -p ./testdata/
     if [ ! -d $TEMP_FOLDER ]; then
 		mkdir -p $TEMP_FOLDER
 		git clone $GIT_SOURCE $TEMP_FOLDER
+		sed -i.bak '370iif(row->rsize > 0)' $TEMP_FOLDER/kilo.c
+		# add debugging output
+		sed -i.bak '243s/(1)/(243)/'     $TEMP_FOLDER/kilo.c
+		sed -i.bak '787s/(1)/(787)/'     $TEMP_FOLDER/kilo.c
+		sed -i.bak '1251s/(1)/(1251)/'   $TEMP_FOLDER/kilo.c
+		sed -i.bak '1259s/(1)/(1259)/'   $TEMP_FOLDER/kilo.c
+		# add debugging file
+		sed -i.bak '53ivoid debug(char *msg){FILE*file;file=fopen("./debug.txt","a");if(file==NULL){exit(53);};fprintf(file,"%s\n",msg);fclose(file);}'  $TEMP_FOLDER/kilo.c
+		# add debug information
+		sed -i.bak '726i{char buffer[500];sprintf(buffer,"line726: filerow=%d",filerow);debug(buffer);}' $TEMP_FOLDER/kilo.c
 	fi
 
 # remove go files from last transpilation
diff --git a/transpiler/operators.go b/transpiler/operators.go
index 549c088..e4909c2 100644
--- a/transpiler/operators.go
+++ b/transpiler/operators.go
@@ -14,6 +14,46 @@ import (
 	"github.com/Konstantin8105/c4go/util"
 )
 
+// ternary without middle operation
+//
+// Example:
+//
+// BinaryConditionalOperator  'int'
+// |-BinaryOperator 'int' '>'
+// | |-IntegerLiteral 'int' 19
+// | `-UnaryOperator 'int' prefix '-'
+// |   `-IntegerLiteral 'int' 9
+// |-OpaqueValueExpr 'int'
+// | `-BinaryOperator 'int' '>'
+// |   |-IntegerLiteral 'int' 19
+// |   `-UnaryOperator 'int' prefix '-'
+// |     `-IntegerLiteral 'int' 9
+// |-OpaqueValueExpr  'int'
+// | `-BinaryOperator  'int' '>'
+// |   |-IntegerLiteral 'int' 19
+// |   `-UnaryOperator 'int' prefix '-'
+// |     `-IntegerLiteral 'int' 9
+// `-IntegerLiteral 0x3646f70 <col:18> 'int' 23
+func transpileBinaryConditionalOperator(n *ast.BinaryConditionalOperator, p *program.Program) (
+	_ *goast.CallExpr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
+	defer func() {
+		if err != nil {
+			err = fmt.Errorf("Cannot transpile BinaryConditionalOperator : err = %v", err)
+		}
+	}()
+
+	var co ast.ConditionalOperator
+	co.Type = n.Type
+	co.AddChild(n.Children()[0])
+	co.AddChild(&ast.IntegerLiteral{
+		Type:  co.Type,
+		Value: "1",
+	})
+	co.AddChild(n.Children()[3])
+
+	return transpileConditionalOperator(&co, p)
+}
+
 // transpileConditionalOperator transpiles a conditional (also known as a
 // ternary) operator:
 //
@@ -27,6 +67,22 @@ import (
 //
 // It is also important to note that C only evaulates the "b" or "c" condition
 // based on the result of "a" (from the above example).
+//
+// Example AST:
+// ConditionalOperator 'int'
+// |-ImplicitCastExpr 'int (*)(int)' <LValueToRValue>
+// | `-DeclRefExpr 'int (*)(int)' lvalue Var 'v' 'int (*)(int)'
+// |-IntegerLiteral 'int' 1
+// `-CallExpr 'int'
+//   |-...
+//
+// ConditionalOperator 'int'
+// |-BinaryOperator 'int' '!='
+// | |-...
+// |-BinaryOperator 'int' '-'
+// | |-...
+// `-BinaryOperator 'int' '-'
+//   |-...
 func transpileConditionalOperator(n *ast.ConditionalOperator, p *program.Program) (
 	_ *goast.CallExpr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
 	defer func() {
diff --git a/transpiler/translation_unit.go b/transpiler/translation_unit.go
index 4557565..156127e 100644
--- a/transpiler/translation_unit.go
+++ b/transpiler/translation_unit.go
@@ -40,6 +40,9 @@ func transpileTranslationUnitDecl(p *program.Program, n *ast.TranslationUnitDecl
 
 	var tryLaterRecordDecl []*ast.RecordDecl
 	for _, sp := range []bool{true, false} {
+		if p.Function == nil {
+			p.DoNotAddComments = sp
+		}
 		for i := 0; i < len(n.Children()); i++ {
 			presentNode := n.Children()[i]
 			if rec, ok := presentNode.(*ast.RecordDecl); ok {
diff --git a/transpiler/transpiler.go b/transpiler/transpiler.go
index c2db294..a294e93 100644
--- a/transpiler/transpiler.go
+++ b/transpiler/transpiler.go
@@ -202,6 +202,9 @@ func transpileToExpr(node ast.Node, p *program.Program, exprIsStmt bool) (
 	case *ast.PredefinedExpr:
 		expr, exprType, err = transpilePredefinedExpr(n, p)
 
+	case *ast.BinaryConditionalOperator:
+		expr, exprType, preStmts, postStmts, err = transpileBinaryConditionalOperator(n, p)
+
 	case *ast.ConditionalOperator:
 		expr, exprType, preStmts, postStmts, err = transpileConditionalOperator(n, p)
 


Test patch:
diff --git a/ast/binary_conditional_operator_test.go b/ast/binary_conditional_operator_test.go
new file mode 100644
index 0000000..c39afae
--- /dev/null
+++ b/ast/binary_conditional_operator_test.go
@@ -0,0 +1,18 @@
+package ast
+
+import (
+	"testing"
+)
+
+func TestBinaryConditionalOperator(t *testing.T) {
+	nodes := map[string]Node{
+		`0x2cdbf90 <col:7, col:16> 'int'`: &BinaryConditionalOperator{
+			Addr:       0x2cdbf90,
+			Pos:        NewPositionFromString("col:7, col:16"),
+			Type:       "int",
+			ChildNodes: []Node{},
+		},
+	}
+
+	runNodeTests(t, nodes)
+}
diff --git a/ast/opaque_value_expr_test.go b/ast/opaque_value_expr_test.go
new file mode 100644
index 0000000..1f4402f
--- /dev/null
+++ b/ast/opaque_value_expr_test.go
@@ -0,0 +1,18 @@
+package ast
+
+import (
+	"testing"
+)
+
+func TestOpaqueValueExpr(t *testing.T) {
+	nodes := map[string]Node{
+		`0x7fa855aab838 <col:63, col:95> 'unsigned long'`: &OpaqueValueExpr{
+			Addr:       0x7fa855aab838,
+			Pos:        NewPositionFromString("col:63, col:95"),
+			Type:       "unsigned long",
+			ChildNodes: []Node{},
+		},
+	}
+
+	runNodeTests(t, nodes)
+}
diff --git a/tests/ternary.c b/tests/ternary.c
index 2f69101..49adc85 100644
--- a/tests/ternary.c
+++ b/tests/ternary.c
@@ -31,7 +31,7 @@ void test_return_ternary()
 
 int main()
 {
-    plan(15);
+    plan(17);
 
     int a = 'a' == 65 ? 10 : 100;
     float b = 10 == 10 ? 1.0 : 2.0;
@@ -97,5 +97,15 @@ int main()
         is_eq(d, 12);
     }
 
+	diag("ternaty without middle");
+	{
+		int a = 42;
+		a = 19 > -9? : 23;
+		is_eq(a, 1);
+		a = 54;
+		a = 4 < -1? : 25;
+		is_eq(a, 25);
+	}
+
     done_testing();
 }
diff --git a/tests/unistd.c b/tests/unistd.c
index c136826..4a545bd 100644
--- a/tests/unistd.c
+++ b/tests/unistd.c
@@ -44,17 +44,20 @@ void test_write()
 
 void test_read()
 {
+    int fd = STDIN_FILENO;
     char data[128];
     for (int i = 0; i < 128; i++) {
         data[i] = '\x00';
     }
     printf("data = %s\n", data);
-    ssize_t s = read(STDIN_FILENO, data, 128);
+    is_streq(data, "");
+    ssize_t s = read(fd, data, 128);
     if (s < 0) {
         fail("not good");
         write(2, "An error occurred in the read.\n", 31);
     }
     printf("data = %s\n", data);
+    is_streq(data, "7");
     is_true(strlen(data) > 0);
 
     diag("wrong read");
@@ -102,7 +105,7 @@ typedef struct {
 
 int main()
 {
-    plan(8);
+    plan(10);
 
     START_TEST(write);
     START_TEST(read);