Skip to content

Commit

Permalink
Add support for function pointers. Fixes #85 and #157 (#469)
Browse files Browse the repository at this point in the history
  • Loading branch information
Konstantin8105 authored and elliotchance committed Dec 18, 2017
1 parent 3bb10db commit 1116413
Show file tree
Hide file tree
Showing 21 changed files with 524 additions and 179 deletions.
9 changes: 6 additions & 3 deletions ast/array_subscript_expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,24 @@ type ArraySubscriptExpr struct {
Addr Address
Pos Position
Type string
Kind string
Type2 string
IsLvalue bool
ChildNodes []Node
}

func parseArraySubscriptExpr(line string) *ArraySubscriptExpr {
groups := groupsFromRegex(
"<(?P<position>.*)> '(?P<type>.*?)' (?P<kind>.*)",
`<(?P<position>.*)> '(?P<type>.*?)'(:'(?P<type2>.*?)')?
(?P<lvalue> lvalue)?`,
line,
)

return &ArraySubscriptExpr{
Addr: ParseAddress(groups["address"]),
Pos: NewPositionFromString(groups["position"]),
Type: groups["type"],
Kind: groups["kind"],
Type2: groups["type2"],
IsLvalue: len(groups["lvalue"]) > 0,
ChildNodes: []Node{},
}
}
Expand Down
11 changes: 10 additions & 1 deletion ast/array_subscript_expr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@ func TestArraySubscriptExpr(t *testing.T) {
Addr: 0x7fe35b85d180,
Pos: NewPositionFromString("col:63, col:69"),
Type: "char *",
Kind: "lvalue",
Type2: "",
IsLvalue: true,
ChildNodes: []Node{},
},
`0x2416660 <col:2, col:5> 'u32':'unsigned int' lvalue`: &ArraySubscriptExpr{
Addr: 0x2416660,
Pos: NewPositionFromString("col:2, col:5"),
Type: "u32",
Type2: "unsigned int",
IsLvalue: true,
ChildNodes: []Node{},
},
}
Expand Down
3 changes: 3 additions & 0 deletions ast/implicit_cast_expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ type ImplicitCastExpr struct {
ChildNodes []Node
}

// ImplicitCastExprArrayToPointerDecay - constant
const ImplicitCastExprArrayToPointerDecay = "ArrayToPointerDecay"

func parseImplicitCastExpr(line string) *ImplicitCastExpr {
groups := groupsFromRegex(
`<(?P<position>.*)>
Expand Down
18 changes: 18 additions & 0 deletions program/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,24 @@ func (p *Program) AddMessage(message string) bool {
}

p.messages = append(p.messages, message)

// Compactizarion warnings stack
if len(p.messages) > 1 {
var (
new = len(p.messages) - 1
last = len(p.messages) - 2
)
// Warning collapsing for minimaze warnings
warning := "// Warning"
if strings.HasPrefix(p.messages[last], warning) {
l := string(p.messages[last][len(warning):])
if strings.HasSuffix(p.messages[new], l) {
p.messages[last] = p.messages[new]
p.messages = p.messages[0:new]
}
}
}

return true
}

Expand Down
37 changes: 27 additions & 10 deletions tests/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ int ff(){ return 3;}

int main()
{
plan(60);
plan(66);

START_TEST(intarr);
START_TEST(doublearr);
Expand All @@ -188,24 +188,41 @@ int main()
a[2] = 42.;
is_eq(a[2],42);

diag("Pointer arithmetic")
diag("Pointer arithmetic. Part 1");
float *b;
b = (float *)calloc(5,sizeof(float));

*b = 42.;
is_eq(*(b+0),42.);
*b = 42.;
is_eq(*(b+0),42.);

*(b+1) = 42.;
is_eq(*(b+1),42.);
*(b+1) = 42.;
is_eq(*(b+1),42.);
*(2+b) = 42.;
is_eq(*(b+2),42.);
is_eq(*(b+2),42.);

*(b+ff()) = 45.;
is_eq(*(b + 3), 45.);
is_eq(*(b + 3), 45.);
*(ff()+b+1) = 46.;
is_eq(*(b + 4), 46.);
is_eq(*(b + 4), 46.);

diag("Pointer arithmetic")
*(b+ (0 ? 1 : 2)) = -1.;
is_eq(*(b+2),-1);

*(b + 0) = 1 ;
*(b + (int)(*(b + 0)) - 1) = 35;
is_eq(*(b+0),35);

*(b + (int)((float)(2))) = -45;
is_eq(*(b+2),-45);

*(b + 1 + 3 + 1 - 5*1 + ff() - 3) = -4.0;
is_eq(*(b+0), -4.0);
is_eq(*b , -4.0);

is_eq((*(b + 1 + 3 + 1 - 5*1 + ff() - 3 + 1) = -48.0,*(b+1)), -48.0);
{int rrr;(void)(rrr);}

diag("Pointer arithmetic. Part 2")
{
float *arr;
arr = (float*)calloc(1+1,sizeof(float));
Expand Down
34 changes: 31 additions & 3 deletions tests/function.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ int mul(int a, int b) {
return a * b;
}

double (*f2)(int, float, double);

double add2 (int a, float b, double c) {
return c+a+b;
}

double mul2 (int a, float b, double c) {
return a*b*c;
}

// Go keywords in C function
int chan() {return 42;}
int defer() {return 42;}
Expand All @@ -42,15 +52,15 @@ int _() {return 42;}

int main()
{
plan(25);
plan(30);

pass("%s", "Main function.");

my_function();

pass("%s", "Back in function main.");

// pointer on function
diag("pointer on function. Part 1")
void * a = NULL;
is_null(a);
a = function;
Expand All @@ -64,13 +74,31 @@ int main()
t();
is_eq(i,50);

// pointer on function
diag("pointer on function. Part 2")
f = add;
int i = f(3,4);
is_eq(i,7);
f = mul;
int j = f(3,4);
is_eq(j,12);
if( f(2,3) == 6 ){
pass("Ok")
}

diag("pointer on function. Part 3")
{
f2 = add2;
double temp_data;
temp_data = f2(4,2,3);
is_eq(temp_data,9);
f2 = mul2;
is_eq(f2(4,2,3),24);
double ttt = f2(1,1,1);
is_eq(ttt,1);
if(add2(2,3,1) == 6.0){
pass("Ok")
}
}

diag("Not allowable function name for Go")
is_eq( chan() , 42);
Expand Down
11 changes: 10 additions & 1 deletion tests/operators.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ void empty(){;}

int main()
{
plan(53);
plan(54);

int i = 10;
signed char j = 1;
Expand Down Expand Up @@ -191,6 +191,15 @@ int main()
{ double *const*az; (void)(az); }
{ int **az; (void)(az); }
{ float *volatile*az; (void)(az); }

diag("CStyleCast <ToVoid> with comma")
{ unsigned int *ui; (void)(empty(),ui);}
{
long int *li;
int counter_li = 0;
(void)(counter_li++,empty(),li);
is_eq(counter_li,1);
}

diag("switch with initialization")
switch(0)
Expand Down
18 changes: 17 additions & 1 deletion tests/struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ struct xx {

int main()
{
plan(20);
plan(23);

struct programming variable;
char *s = "Programming in Software Development.";
Expand Down Expand Up @@ -169,5 +169,21 @@ int main()
is_eq(followingSteps[0].possibleSteps, 1);
}

diag("Double typedef type")
{
typedef int int2;
typedef int2 int3;
typedef int3 int4;

is_eq((int)((int4)((int3)((int2)(42)))),42);
}
{
typedef size_t size2;
is_eq(((size2)((size_t)(56))),56.0)
}
{
is_eq((size_t)(43),43);
}

done_testing();
}
13 changes: 12 additions & 1 deletion tests/ternary.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#include <stdio.h>
#include "tests.h"

void f_empty(){
return;
};

int main()
{
plan(8);
plan(9);

int a = 'a' == 65 ? 10 : 100;
float b = 10 == 10 ? 1.0 : 2.0;
Expand All @@ -30,5 +34,12 @@ int main()
pass(__func__);
}

diag("CStyleCast <ToVoid>")
{double a, b; 0 ? (void)(a) : (void)(b); (void)(a),(void)(b); }
{double a ; 0 ? (void)(a) : f_empty(); (void)(a);}
{double b; 0 ? f_empty() : (void)(b); (void)(b);}
{ ; 0 ? f_empty() : f_empty(); }
pass("Ok - ToVoid");

done_testing();
}
42 changes: 28 additions & 14 deletions transpiler/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ import (
// logical operators like "==", "!=", ...
func transpileBinaryOperatorComma(n *ast.BinaryOperator, p *program.Program) (
stmt goast.Stmt, preStmts []goast.Stmt, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("Cannot transpile operator comma : err = %v", err)
p.AddMessage(p.GenerateWarningMessage(err, n))
}
}()

left, err := transpileToStmts(n.Children()[0], p)
if err != nil {
Expand All @@ -40,15 +46,19 @@ func transpileBinaryOperatorComma(n *ast.BinaryOperator, p *program.Program) (
}

preStmts = append(preStmts, left...)
if len(right) > 1 {
preStmts = append(preStmts, right[:len(right)-1]...)
}

return right[0], preStmts, nil
return right[len(right)-1], preStmts, nil
}

func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsStmt bool) (
_ goast.Expr, resultType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("Cannot transpile BinaryOperator : result type = {%s}. Error: %v", resultType, err)
p.AddMessage(p.GenerateWarningMessage(err, n))
}
}()

Expand Down Expand Up @@ -136,19 +146,25 @@ 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, st, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false)
stmts, _, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false)
if err != nil {
return nil, "unknown50", nil, nil, err
}
preStmts = append(preStmts, newPre...)
preStmts = append(preStmts, util.NewExprStmt(stmts))
postStmts = append(postStmts, newPost...)
preStmts = append(preStmts, newPost...)

var st string
stmts, st, newPre, newPost, err = transpileToExpr(n.Children()[1], p, false)
if err != nil {
return nil, "unknown51", nil, nil, err
}
preStmts = append(preStmts, newPre...)
postStmts = append(postStmts, newPost...)
// Theoretically , we don't have any preStmts or postStmts
// from n.Children()[1]
if len(newPre) > 0 || len(newPost) > 0 {
p.AddMessage(p.GenerateWarningMessage(
fmt.Errorf("Not support lenght pre or post stmts: {%d,%d}", len(newPre), len(newPost)), n))
}
return stmts, st, preStmts, postStmts, nil
}

Expand Down Expand Up @@ -206,16 +222,14 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsSt
leftType, preStmts, postStmts, nil
}

if operator == token.NEQ || operator == token.EQL {
// Convert "(0)" to "nil" when we are dealing with equality.
if types.IsNullExpr(right) {
right = util.NewNil()
} else {
// We may have to cast the right side to the same type as the left
// 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.NEQ || operator == token.EQL || operator == token.LSS || operator == token.GTR || operator == token.AND {
// We may have to cast the right side to the same type as the left
// 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 rightType != types.NullPointer {
right, err = types.CastExpr(p, right, rightType, leftType)
rightType = leftType
p.AddMessage(p.GenerateWarningOrErrorMessage(err, n, right == nil))
}
}
Expand Down
Loading

0 comments on commit 1116413

Please sign in to comment.