Skip to content

Commit

Permalink
Improved double equal handling. Fixes #565 (#696)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamphaus authored and elliotchance committed May 2, 2018
1 parent 4d0afe8 commit e1f3d12
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 19 deletions.
38 changes: 37 additions & 1 deletion tests/operators.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@ double * return_null(){
return NULL;
}

typedef struct doubleEqual{
int a;
unsigned int b;
} doubleEqual;

int main()
{
plan(99);
plan(114);

int i = 10;
signed char j = 1;
Expand Down Expand Up @@ -325,6 +330,37 @@ int main()
is_eq(*a, 42);
is_eq(*b, 42);
}
{
doubleEqual de;
de.a = de.b = 42;
is_eq(de.a, 42);
is_eq(de.b, 42);
doubleEqual *dep = &de;
dep->a = dep->b = 9;
is_eq(dep->a, 9);
is_eq(dep->b, 9);
de.a += de.b -= 2;
is_eq(de.a, 16);
is_eq(de.b, 7);
int n,m,p;
n = m = p = 0;
for(de.a = de.b = 0; de.a < 2; de.b = de.a++) {
is_eq(n, de.a);
n = m = ++p ;
is_eq(n-1, de.a);
}
is_eq(de.a, 2);
is_eq(de.b, 1);
is_eq(n, 2);
is_eq(m, 2);
switch(de.a = de.b = 42) {
case 42:
pass("switch equals a=b=");
break;
default:
fail("code should not reach here");
}
}
{
int yy = 0;
if ((yy = simple_repeat(42)) > 3)
Expand Down
9 changes: 4 additions & 5 deletions transpiler/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,8 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
bComma.AddChild(c)
bComma.AddChild(&bSecond)

// exprIsStmt now changes to false to stop any AST children from
// not being safely wrapped in a closure.
return transpileBinaryOperator(&bComma, p, false)
// goast.NewBinaryExpr takes care to wrap any AST children safely in a closure, if needed.
return transpileBinaryOperator(&bComma, p, exprIsStmt)
}
}
}
Expand Down Expand Up @@ -191,7 +190,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
// | `-ImplicitCastExpr 0x21a7898 <col:6> 'int' <LValueToRValue>
// | `-DeclRefExpr 0x21a7870 <col:6> 'int' lvalue Var 0x21a7748 'y' 'int'
if getTokenForOperator(n.Operator) == token.COMMA {
stmts, _, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false)
stmts, _, newPre, newPost, err := transpileToExpr(n.Children()[0], p, exprIsStmt)
if err != nil {
return nil, "unknown50", nil, nil, err
}
Expand All @@ -200,7 +199,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
preStmts = append(preStmts, newPost...)

var st string
stmts, st, newPre, newPost, err = transpileToExpr(n.Children()[1], p, false)
stmts, st, newPre, newPost, err = transpileToExpr(n.Children()[1], p, exprIsStmt)
if err != nil {
return nil, "unknown51", nil, nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion transpiler/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func getName(p *program.Program, firstChild ast.Node) (name string, err error) {

case *ast.ArraySubscriptExpr:
var expr goast.Expr
expr, _, _, _, err = transpileArraySubscriptExpr(fc, p)
expr, _, _, _, err = transpileArraySubscriptExpr(fc, p, false)
if err != nil {
return
}
Expand Down
6 changes: 4 additions & 2 deletions transpiler/operators.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,8 @@ func atomicOperation(n ast.Node, p *program.Program) (
return
}

// since we will explicitly use an anonymous function, we can transpileToExpr as a statement
expr, exprType, preStmts, postStmts, err = transpileToExpr(n, p, true)
expr = util.NewAnonymousFunction(append(preStmts, &goast.ExprStmt{expr}),
postStmts,
util.NewIdent(varName),
Expand Down Expand Up @@ -812,7 +814,7 @@ func atomicOperation(n ast.Node, p *program.Program) (
// `-DeclRefExpr 0x3c42400 <col:32> 'int' lvalue Var 0x3c3cf60 'iterator' 'int'
varName := "tempVar"

expr, exprType, preStmts, postStmts, err = transpileToExpr(v.Children()[0], p, false)
expr, exprType, preStmts, postStmts, err = transpileToExpr(v.Children()[0], p, true)
if err != nil {
return
}
Expand Down Expand Up @@ -891,7 +893,7 @@ func atomicOperation(n ast.Node, p *program.Program) (
return
}

e, _, newPre, newPost, _ := transpileToExpr(v, p, false)
e, _, newPre, newPost, _ := transpileToExpr(v, p, true)
body := combineStmts(&goast.ExprStmt{e}, newPre, newPost)

expr, exprType, _, _, _ = atomicOperation(v.Children()[0], p)
Expand Down
4 changes: 2 additions & 2 deletions transpiler/transpiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,13 @@ func transpileToExpr(node ast.Node, p *program.Program, exprIsStmt bool) (
expr, exprType, preStmts, postStmts, err = transpileConditionalOperator(n, p)

case *ast.ArraySubscriptExpr:
expr, exprType, preStmts, postStmts, err = transpileArraySubscriptExpr(n, p)
expr, exprType, preStmts, postStmts, err = transpileArraySubscriptExpr(n, p, exprIsStmt)

case *ast.BinaryOperator:
expr, exprType, preStmts, postStmts, err = transpileBinaryOperator(n, p, exprIsStmt)

case *ast.UnaryOperator:
expr, exprType, preStmts, postStmts, err = transpileUnaryOperator(n, p)
expr, exprType, preStmts, postStmts, err = transpileUnaryOperator(n, p, exprIsStmt)

case *ast.MemberExpr:
expr, exprType, preStmts, postStmts, err = transpileMemberExpr(n, p)
Expand Down
20 changes: 15 additions & 5 deletions transpiler/unary.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"go/token"
)

func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operator token.Token) (
func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operator token.Token, exprIsStmt bool) (
expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
defer func() {
if err != nil {
Expand Down Expand Up @@ -76,6 +76,16 @@ func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operato
Op: token.ASSIGN,
Y: expr,
}
if !exprIsStmt {
var lType string
lType, err = types.ResolveType(p, leftType)
if err != nil {
return
}
expr = util.NewAnonymousFunction([]goast.Stmt{&goast.ExprStmt{
X: expr,
}}, nil, goast.NewIdent(name), lType)
}
return
}

Expand Down Expand Up @@ -119,7 +129,7 @@ func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operato
ChildNodes: []ast.Node{},
},
},
}, p, false)
}, p, exprIsStmt)
}

func transpileUnaryOperatorNot(n *ast.UnaryOperator, p *program.Program) (
Expand Down Expand Up @@ -572,7 +582,7 @@ func transpilePointerArith(n *ast.UnaryOperator, p *program.Program) (
return nil, "", nil, nil, fmt.Errorf("Cannot found : %#v", pointer)
}

func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program) (
func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program, exprIsStmt bool) (
_ goast.Expr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
defer func() {
if err != nil {
Expand All @@ -591,15 +601,15 @@ func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program) (
// *(t + 1) = ...
return transpilePointerArith(n, p)
case token.INC, token.DEC: // ++, --
return transpileUnaryOperatorInc(n, p, operator)
return transpileUnaryOperatorInc(n, p, operator, exprIsStmt)
case token.NOT: // !
return transpileUnaryOperatorNot(n, p)
case token.AND: // &
return transpileUnaryOperatorAmpersant(n, p)
}

// Otherwise handle like a unary operator.
e, eType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false)
e, eType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, exprIsStmt)
if err != nil {
return nil, "", nil, nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions transpiler/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ func transpileDeclStmt(n *ast.DeclStmt, p *program.Program) (stmts []goast.Stmt,
return
}

func transpileArraySubscriptExpr(n *ast.ArraySubscriptExpr, p *program.Program) (
func transpileArraySubscriptExpr(n *ast.ArraySubscriptExpr, p *program.Program, exprIsStmt bool) (
_ *goast.IndexExpr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
defer func() {
if err != nil {
Expand All @@ -314,7 +314,7 @@ func transpileArraySubscriptExpr(n *ast.ArraySubscriptExpr, p *program.Program)

children := n.Children()

expression, _, newPre, newPost, err := transpileToExpr(children[0], p, false)
expression, _, newPre, newPost, err := transpileToExpr(children[0], p, exprIsStmt)
if err != nil {
return nil, "", nil, nil, err
}
Expand Down
26 changes: 25 additions & 1 deletion util/goast.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,33 @@ func NewBinaryExpr(left goast.Expr, operator token.Token, right goast.Expr,
Op: operator,
Y: right,
}
if !stmt && isAssignishOperator(operator) {
return NewFuncClosure(returnType, NewExprStmt(b), &goast.ReturnStmt{
Results: []goast.Expr{left},
})
}
return b
}

func isAssignishOperator(t token.Token) bool {
switch t {
case token.ADD_ASSIGN, // +=
token.SUB_ASSIGN, // -=
token.MUL_ASSIGN, // *=
token.QUO_ASSIGN, // /=
token.REM_ASSIGN, // %=
token.AND_ASSIGN, // &=
token.OR_ASSIGN, // |=
token.XOR_ASSIGN, // ^=
token.SHL_ASSIGN, // <<=
token.SHR_ASSIGN, // >>=
token.AND_NOT_ASSIGN, // &^=
token.ASSIGN: // =
return true
}
return false
}

// NewIdent - create a new Go ast Ident
func NewIdent(name string) *goast.Ident {
// TODO: The name of a variable or field cannot be a reserved word
Expand Down Expand Up @@ -453,7 +477,7 @@ func NewAnonymousFunction(body, deferBody []goast.Stmt,
returnValue goast.Expr,
returnType string) *goast.CallExpr {

if deferBody != nil {
if len(deferBody) > 0 {
body = append(body, []goast.Stmt{&goast.DeferStmt{
Defer: 1,
Call: &goast.CallExpr{
Expand Down

0 comments on commit e1f3d12

Please sign in to comment.