Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More sane error reporting #112

Merged
merged 6 commits into from
May 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
package ast

import (
"fmt"
"reflect"
"regexp"
"strings"
)
Expand All @@ -11,6 +13,208 @@ type Node interface {
AddChild(node Node)
}

// Position returns the position of the node in the original file. If the
// position cannot be determined an empty string is returned.
func Position(node Node) string {
switch n := node.(type) {
case *AlignedAttr:
return n.Position
case *AlwaysInlineAttr:
return n.Position
case *ArraySubscriptExpr:
return n.Position
case *AsmLabelAttr:
return n.Position
case *AvailabilityAttr:
return n.Position
case *BinaryOperator:
return n.Position
case *BreakStmt:
return n.Position
case *BuiltinType:
return ""
case *CallExpr:
return n.Position
case *CaseStmt:
return n.Position
case *CharacterLiteral:
return n.Position
case *CompoundStmt:
return n.Position
case *ConditionalOperator:
return n.Position
case *ConstAttr:
return n.Position
case *ConstantArrayType:
return ""
case *ContinueStmt:
return n.Position
case *CompoundAssignOperator:
return n.Position
case *CStyleCastExpr:
return n.Position
case *DeclRefExpr:
return n.Position
case *DeclStmt:
return n.Position
case *DefaultStmt:
return n.Position
case *DeprecatedAttr:
return n.Position
case *DoStmt:
return n.Position
case *ElaboratedType:
return ""
case *Enum:
return ""
case *EnumConstantDecl:
return n.Position
case *EnumDecl:
return n.Position
case *EnumType:
return ""
case *FieldDecl:
return n.Position
case *FloatingLiteral:
return n.Position
case *FormatAttr:
return n.Position
case *FunctionDecl:
return n.Position
case *FunctionProtoType:
return ""
case *ForStmt:
return n.Position
case *GotoStmt:
return n.Position
case *IfStmt:
return n.Position
case *ImplicitCastExpr:
return n.Position
case *ImplicitValueInitExpr:
return n.Position
case *IncompleteArrayType:
return ""
case *InitListExpr:
return n.Position
case *IntegerLiteral:
return n.Position
case *LabelStmt:
return n.Position
case *MallocAttr:
return n.Position
case *MaxFieldAlignmentAttr:
return n.Position
case *MemberExpr:
return n.Position
case *ModeAttr:
return n.Position
case *NoInlineAttr:
return n.Position
case *NoThrowAttr:
return n.Position
case *NonNullAttr:
return n.Position
case *OffsetOfExpr:
return n.Position
case *PackedAttr:
return n.Position
case *ParenExpr:
return n.Position
case *ParenType:
return ""
case *ParmVarDecl:
return n.Position
case *PointerType:
return ""
case *PredefinedExpr:
return n.Position
case *PureAttr:
return n.Position
case *QualType:
return ""
case *Record:
return ""
case *RecordDecl:
return n.Position
case *RecordType:
return ""
case *RestrictAttr:
return n.Position
case *ReturnStmt:
return n.Position
case *ReturnsTwiceAttr:
return n.Position
case *StringLiteral:
return n.Position
case *SwitchStmt:
return n.Position
case *TranslationUnitDecl:
return ""
case *TransparentUnionAttr:
return n.Position
case *Typedef:
return ""
case *TypedefDecl:
return n.Position
case *TypedefType:
return ""
case *UnaryExprOrTypeTraitExpr:
return n.Position
case *UnaryOperator:
return n.Position
case *VAArgExpr:
return n.Position
case *VarDecl:
return n.Position
case *WarnUnusedResultAttr:
return n.Position
case *WhileStmt:
return n.Position
default:
panic(n)
}
}

// getNicerLineNumber tries to extract a more useful line number from a
// position. If the line number cannot be determined then the original location
// string is returned.
func getNicerLineNumber(s string) string {
matches := regexp.MustCompile(`line:(\d+)`).FindStringSubmatch(s)
if len(matches) > 0 {
return fmt.Sprintf("line %s", matches[1])
}

return s
}

func CheckError(e error, n Node) {
if e != nil {
structName := reflect.TypeOf(n).Elem().Name()
fmt.Printf("// Error (%s): %s: %s\n", structName,
getNicerLineNumber(Position(n)), e.Error())
panic(e)
}
}

func IsWarning(e error, n Node) bool {
if e != nil {
structName := reflect.TypeOf(n).Elem().Name()
fmt.Printf("// Warning (%s): %s: %s\n", structName,
getNicerLineNumber(Position(n)), e.Error())
}

return e != nil
}

func WarningOrError(e error, n Node, isError bool) {
if isError {
CheckError(e, n)
} else {
IsWarning(e, n)
}
}

// Parse takes the coloured output of the clang AST command and returns a root
// node for the AST.
func Parse(line string) Node {
Expand Down
3 changes: 3 additions & 0 deletions program/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ func NewStruct(n *ast.RecordDecl) *Struct {
case *ast.RecordDecl:
fields[f.Name] = NewStruct(f)

case *ast.MaxFieldAlignmentAttr, *ast.AlignedAttr:
// FIXME: Should these really be ignored?

default:
panic(fmt.Sprintf("cannot decode: %#v", f))
}
Expand Down
42 changes: 27 additions & 15 deletions transpiler/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) (
*goast.BinaryExpr, string, []goast.Stmt, []goast.Stmt, error) {
preStmts := []goast.Stmt{}
postStmts := []goast.Stmt{}
var err error

left, leftType, newPre, newPost, err := transpileToExpr(n.Children[0], p)
if err != nil {
Expand All @@ -35,20 +36,29 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) (
returnType := types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType)

if operator == token.LAND {
left = types.CastExpr(p, left, leftType, "bool")
right = types.CastExpr(p, right, rightType, "bool")

return &goast.BinaryExpr{
X: left,
Op: operator,
Y: right,
}, "bool", preStmts, postStmts, nil
left, err = types.CastExpr(p, left, leftType, "bool")
ast.WarningOrError(err, n, left == nil)
if left == nil {
left = util.NewStringLit("nil")
}

right, err = types.CastExpr(p, right, rightType, "bool")
ast.WarningOrError(err, n, right == nil)
if right == nil {
right = util.NewStringLit("nil")
}

return util.NewBinaryExpr(left, operator, right), "bool",
preStmts, postStmts, nil
}

// Convert "(0)" to "nil" when we are dealing with equality.
if (operator == token.NEQ || operator == token.EQL) &&
types.IsNullExpr(right) {
if types.ResolveType(p, leftType) == "string" {
t, err := types.ResolveType(p, leftType)
ast.IsWarning(err, n)

if t == "string" {
p.AddImport("github.com/elliotchance/c2go/noarch")
left = util.NewCallExpr("noarch.NullTerminatedString", left)
right = &goast.BasicLit{
Expand All @@ -61,12 +71,14 @@ func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program) (
}

if operator == token.ASSIGN {
right = types.CastExpr(p, right, rightType, returnType)
right, err = types.CastExpr(p, right, rightType, returnType)

if ast.IsWarning(err, n) && right == nil {
right = util.NewStringLit("nil")
}
}

return &goast.BinaryExpr{
X: left,
Op: operator,
Y: right,
}, types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType), preStmts, postStmts, nil
return util.NewBinaryExpr(left, operator, right),
types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType),
preStmts, postStmts, nil
}
35 changes: 30 additions & 5 deletions transpiler/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/elliotchance/c2go/ast"
"github.com/elliotchance/c2go/program"
"github.com/elliotchance/c2go/types"
"github.com/elliotchance/c2go/util"

goast "go/ast"
)
Expand Down Expand Up @@ -65,7 +66,12 @@ func transpileIfStmt(n *ast.IfStmt, p *program.Program) (
}

// The condition in Go must always be a bool.
boolCondition := types.CastExpr(p, conditional, conditionalType, "bool")
boolCondition, err := types.CastExpr(p, conditional, conditionalType, "bool")
ast.WarningOrError(err, n, boolCondition == nil)

if boolCondition == nil {
boolCondition = util.NewStringLit("nil")
}

body, newPre, newPost, err := transpileToBlockStmt(children[2], p)
if err != nil {
Expand Down Expand Up @@ -157,7 +163,12 @@ func transpileForStmt(n *ast.ForStmt, p *program.Program) (

preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

condition = types.CastExpr(p, condition, conditionType, "bool")
condition, err = types.CastExpr(p, condition, conditionType, "bool")
ast.WarningOrError(err, n, condition == nil)

if condition == nil {
condition = util.NewStringLit("nil")
}
}

return &goast.ForStmt{
Expand Down Expand Up @@ -191,8 +202,15 @@ func transpileWhileStmt(n *ast.WhileStmt, p *program.Program) (

preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

cond, err := types.CastExpr(p, condition, conditionType, "bool")
ast.WarningOrError(err, n, cond == nil)

if cond == nil {
cond = util.NewStringLit("nil")
}

return &goast.ForStmt{
Cond: types.CastExpr(p, condition, conditionType, "bool"),
Cond: cond,
Body: body,
}, preStmts, postStmts, nil
}
Expand All @@ -217,11 +235,18 @@ func transpileDoStmt(n *ast.DoStmt, p *program.Program) (

preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost)

// Add IfStmt to the end of the loop to check the condition
// Add IfStmt to the end of the loop to check the condition.
x, err := types.CastExpr(p, condition, conditionType, "bool")
ast.WarningOrError(err, n, x == nil)

if x == nil {
x = util.NewStringLit("nil")
}

body.List = append(body.List, &goast.IfStmt{
Cond: &goast.UnaryExpr{
Op: token.NOT,
X: types.CastExpr(p, condition, conditionType, "bool"),
X: x,
},
Body: &goast.BlockStmt{
List: []goast.Stmt{&goast.BranchStmt{Tok: token.BREAK}},
Expand Down
Loading