From 75540be93c035d9c5d3890711917ac7a4f35bc4a Mon Sep 17 00:00:00 2001 From: Ben Sheffield Date: Sun, 16 Apr 2017 18:17:40 +0100 Subject: [PATCH] Refactored ast nodes into seperate package. --- ast.go | 163 --------------- .../always_inline_attr.go | 6 +- .../array_subscript_expr.go | 14 +- asm_label_attr.go => ast/asm_label_attr.go | 6 +- ast/ast.go | 196 ++++++++++++++++++ ast_test.go => ast/ast_test.go | 2 +- .../availability_attr.go | 6 +- binary_operator.go => ast/binary_operator.go | 25 +-- break_stmt.go => ast/break_stmt.go | 6 +- builtin_type.go => ast/builtin_type.go | 6 +- .../c_style_cast_expr.go | 10 +- call_expr.go => ast/call_expr.go | 25 ++- cast.go => ast/cast.go | 10 +- .../character_literal.go | 6 +- common.go => ast/common.go | 31 +-- compound_stmt.go => ast/compound_stmt.go | 19 +- ast/conditional_operator.go | 34 +++ const_attr.go => ast/const_attr.go | 6 +- .../constant_array_type.go | 10 +- decl_ref_expr.go => ast/decl_ref_expr.go | 10 +- decl_stmt.go => ast/decl_stmt.go | 15 +- deprecated_attr.go => ast/deprecated_attr.go | 6 +- elaborated_type.go => ast/elaborated_type.go | 10 +- enum.go => ast/enum.go | 6 +- .../enum_constant_decl.go | 10 +- enum_decl.go => ast/enum_decl.go | 10 +- enum_type.go => ast/enum_type.go | 10 +- field_decl.go => ast/field_decl.go | 16 +- .../floating_literal.go | 6 +- for_stmt.go => ast/for_stmt.go | 27 +-- format_attr.go => ast/format_attr.go | 6 +- function_decl.go => ast/function_decl.go | 50 +++-- .../function_definition.go | 2 +- .../function_proto_type.go | 10 +- if_stmt.go => ast/if_stmt.go | 28 +-- .../implicit_cast_expr.go | 10 +- integer_literal.go => ast/integer_literal.go | 6 +- malloc_attr.go => ast/malloc_attr.go | 6 +- member_expr.go => ast/member_expr.go | 20 +- mode_attr.go => ast/mode_attr.go | 6 +- no_throw_attr.go => ast/no_throw_attr.go | 6 +- non_null_attr.go => ast/non_null_attr.go | 6 +- paren_expr.go => ast/paren_expr.go | 13 +- parm_var_decl.go => ast/parm_var_decl.go | 10 +- pointer_type.go => ast/pointer_type.go | 10 +- predefined_expr.go => ast/predefined_expr.go | 13 +- qual_type.go => ast/qual_type.go | 10 +- record.go => ast/record.go | 6 +- record_decl.go => ast/record_decl.go | 21 +- record_type.go => ast/record_type.go | 10 +- resolve.go => ast/resolve.go | 21 +- restrict_attr.go => ast/restrict_attr.go | 6 +- ast/return_stmt.go | 38 ++++ string_literal.go => ast/string_literal.go | 10 +- ast/translation_unit_decl.go | 29 +++ typedef.go => ast/typedef.go | 6 +- typedef_decl.go => ast/typedef_decl.go | 28 +-- typedef_type.go => ast/typedef_type.go | 10 +- unary_operator.go => ast/unary_operator.go | 28 +-- util.go => ast/util.go | 2 +- var_decl.go => ast/var_decl.go | 30 ++- while_stmt.go => ast/while_stmt.go | 21 +- conditional_operator.go | 36 ---- import.go | 35 ---- main.go | 47 +++-- main_test.go | 5 +- return_stmt.go | 33 --- translation_unit_decl.go | 23 -- 68 files changed, 769 insertions(+), 595 deletions(-) delete mode 100644 ast.go rename always_inline_attr.go => ast/always_inline_attr.go (79%) rename array_subscript_expr.go => ast/array_subscript_expr.go (61%) rename asm_label_attr.go => ast/asm_label_attr.go (82%) create mode 100644 ast/ast.go rename ast_test.go => ast/ast_test.go (99%) rename availability_attr.go => ast/availability_attr.go (91%) rename binary_operator.go => ast/binary_operator.go (55%) rename break_stmt.go => ast/break_stmt.go (78%) rename builtin_type.go => ast/builtin_type.go (78%) rename c_style_cast_expr.go => ast/c_style_cast_expr.go (73%) rename call_expr.go => ast/call_expr.go (66%) rename cast.go => ast/cast.go (73%) rename character_literal.go => ast/character_literal.go (83%) rename common.go => ast/common.go (61%) rename compound_stmt.go => ast/compound_stmt.go (63%) create mode 100644 ast/conditional_operator.go rename const_attr.go => ast/const_attr.go (81%) rename constant_array_type.go => ast/constant_array_type.go (72%) rename decl_ref_expr.go => ast/decl_ref_expr.go (86%) rename decl_stmt.go => ast/decl_stmt.go (56%) rename deprecated_attr.go => ast/deprecated_attr.go (84%) rename elaborated_type.go => ast/elaborated_type.go (71%) rename enum.go => ast/enum.go (77%) rename enum_constant_decl.go => ast/enum_constant_decl.go (78%) rename enum_decl.go => ast/enum_decl.go (76%) rename enum_type.go => ast/enum_type.go (66%) rename field_decl.go => ast/field_decl.go (79%) rename floating_literal.go => ast/floating_literal.go (80%) rename for_stmt.go => ast/for_stmt.go (69%) rename format_attr.go => ast/format_attr.go (89%) rename function_decl.go => ast/function_decl.go (65%) rename function_definition.go => ast/function_definition.go (99%) rename function_proto_type.go => ast/function_proto_type.go (72%) rename if_stmt.go => ast/if_stmt.go (70%) rename implicit_cast_expr.go => ast/implicit_cast_expr.go (72%) rename integer_literal.go => ast/integer_literal.go (82%) rename malloc_attr.go => ast/malloc_attr.go (78%) rename member_expr.go => ast/member_expr.go (62%) rename mode_attr.go => ast/mode_attr.go (81%) rename no_throw_attr.go => ast/no_throw_attr.go (78%) rename non_null_attr.go => ast/non_null_attr.go (78%) rename paren_expr.go => ast/paren_expr.go (62%) rename parm_var_decl.go => ast/parm_var_decl.go (87%) rename pointer_type.go => ast/pointer_type.go (67%) rename predefined_expr.go => ast/predefined_expr.go (71%) rename qual_type.go => ast/qual_type.go (71%) rename record.go => ast/record.go (77%) rename record_decl.go => ast/record_decl.go (74%) rename record_type.go => ast/record_type.go (67%) rename resolve.go => ast/resolve.go (91%) rename restrict_attr.go => ast/restrict_attr.go (81%) create mode 100644 ast/return_stmt.go rename string_literal.go => ast/string_literal.go (75%) create mode 100644 ast/translation_unit_decl.go rename typedef.go => ast/typedef.go (77%) rename typedef_decl.go => ast/typedef_decl.go (76%) rename typedef_type.go => ast/typedef_type.go (71%) rename unary_operator.go => ast/unary_operator.go (53%) rename util.go => ast/util.go (98%) rename var_decl.go => ast/var_decl.go (67%) rename while_stmt.go => ast/while_stmt.go (51%) delete mode 100644 conditional_operator.go delete mode 100644 import.go delete mode 100644 return_stmt.go delete mode 100644 translation_unit_decl.go diff --git a/ast.go b/ast.go deleted file mode 100644 index fa964eea9..000000000 --- a/ast.go +++ /dev/null @@ -1,163 +0,0 @@ -package main - -import ( - "bytes" - "regexp" - "strings" -) - -type ExpressionRenderer interface { - // TODO: The two arguments returned are the rendered Go and the C type. - // This should be made into an appropriate type. - Render() []string -} - -type LineRenderer interface { - RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) -} - -func Parse(line string) interface{} { - nodeName := strings.SplitN(line, " ", 2)[0] - var node interface{} - - switch nodeName { - case "AlwaysInlineAttr": - node = parseAlwaysInlineAttr(line) - case "ArraySubscriptExpr": - node = parseArraySubscriptExpr(line) - case "AsmLabelAttr": - node = parseAsmLabelAttr(line) - case "AvailabilityAttr": - node = parseAvailabilityAttr(line) - case "BinaryOperator": - node = parseBinaryOperator(line) - case "BreakStmt": - node = parseBreakStmt(line) - case "BuiltinType": - node = parseBuiltinType(line) - case "CallExpr": - node = parseCallExpr(line) - case "CharacterLiteral": - node = parseCharacterLiteral(line) - case "CompoundStmt": - node = parseCompoundStmt(line) - case "ConditionalOperator": - node = parseConditionalOperator(line) - case "ConstAttr": - node = parseConstAttr(line) - case "ConstantArrayType": - node = parseConstantArrayType(line) - case "CStyleCastExpr": - node = parseCStyleCastExpr(line) - case "DeclRefExpr": - node = parseDeclRefExpr(line) - case "DeclStmt": - node = parseDeclStmt(line) - case "DeprecatedAttr": - node = parseDeprecatedAttr(line) - case "ElaboratedType": - node = parseElaboratedType(line) - case "Enum": - node = parseEnum(line) - case "EnumConstantDecl": - node = parseEnumConstantDecl(line) - case "EnumDecl": - node = parseEnumDecl(line) - case "EnumType": - node = parseEnumType(line) - case "FieldDecl": - node = parseFieldDecl(line) - case "FloatingLiteral": - node = parseFloatingLiteral(line) - case "FormatAttr": - node = parseFormatAttr(line) - case "FunctionDecl": - node = parseFunctionDecl(line) - case "FunctionProtoType": - node = parseFunctionProtoType(line) - case "ForStmt": - node = parseForStmt(line) - case "IfStmt": - node = parseIfStmt(line) - case "ImplicitCastExpr": - node = parseImplicitCastExpr(line) - case "IntegerLiteral": - node = parseIntegerLiteral(line) - case "MallocAttr": - node = parseMallocAttr(line) - case "MemberExpr": - node = parseMemberExpr(line) - case "ModeAttr": - node = parseModeAttr(line) - case "NoThrowAttr": - node = parseNoThrowAttr(line) - case "NonNullAttr": - node = parseNonNullAttr(line) - case "ParenExpr": - node = parseParenExpr(line) - case "ParmVarDecl": - node = parseParmVarDecl(line) - case "PointerType": - node = parsePointerType(line) - case "PredefinedExpr": - node = parsePredefinedExpr(line) - case "QualType": - node = parseQualType(line) - case "Record": - node = parseRecord(line) - case "RecordDecl": - node = parseRecordDecl(line) - case "RecordType": - node = parseRecordType(line) - case "RestrictAttr": - node = parseRestrictAttr(line) - case "ReturnStmt": - node = parseReturnStmt(line) - case "StringLiteral": - node = parseStringLiteral(line) - case "TranslationUnitDecl": - node = parseTranslationUnitDecl(line) - case "Typedef": - node = parseTypedef(line) - case "TypedefDecl": - node = parseTypedefDecl(line) - case "TypedefType": - node = parseTypedefType(line) - case "UnaryOperator": - node = parseUnaryOperator(line) - case "VarDecl": - node = parseVarDecl(line) - case "WhileStmt": - node = parseWhileStmt(line) - case "NullStmt": - node = nil - default: - panic("Unknown node type: '" + line + "'") - } - - return node -} - -func groupsFromRegex(rx, line string) map[string]string { - // We remove tabs and newlines from the regex. This is purely cosmetic, - // as the regex input can be quite long and it's nice for the caller to - // be able to format it in a more readable way. - fullRegexp := "(?P
[0-9a-fx]+) " + - strings.Replace(strings.Replace(rx, "\n", "", -1), "\t", "", -1) - re := regexp.MustCompile(fullRegexp) - - match := re.FindStringSubmatch(line) - if len(match) == 0 { - panic("could not match regexp '" + fullRegexp + - "' with string '" + line + "'") - } - - result := make(map[string]string) - for i, name := range re.SubexpNames() { - if i != 0 { - result[name] = match[i] - } - } - - return result -} diff --git a/always_inline_attr.go b/ast/always_inline_attr.go similarity index 79% rename from always_inline_attr.go rename to ast/always_inline_attr.go index cde351b27..388e2714e 100644 --- a/always_inline_attr.go +++ b/ast/always_inline_attr.go @@ -1,4 +1,4 @@ -package main +package ast type AlwaysInlineAttr struct { Address string @@ -18,3 +18,7 @@ func parseAlwaysInlineAttr(line string) *AlwaysInlineAttr { Children: []interface{}{}, } } + +func (n *AlwaysInlineAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/array_subscript_expr.go b/ast/array_subscript_expr.go similarity index 61% rename from array_subscript_expr.go rename to ast/array_subscript_expr.go index 1516aeb38..38ba5a38a 100644 --- a/array_subscript_expr.go +++ b/ast/array_subscript_expr.go @@ -1,4 +1,4 @@ -package main +package ast import "fmt" @@ -7,7 +7,7 @@ type ArraySubscriptExpr struct { Position string Type string Kind string - Children []interface{} + Children []Node } func parseArraySubscriptExpr(line string) *ArraySubscriptExpr { @@ -21,12 +21,14 @@ func parseArraySubscriptExpr(line string) *ArraySubscriptExpr { Position: groups["position"], Type: groups["type"], Kind: groups["kind"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *ArraySubscriptExpr) Render() []string { +func (n *ArraySubscriptExpr) render(ast *Ast) (string, string) { children := n.Children - return []string{fmt.Sprintf("%s[%s]", renderExpression(children[0])[0], - renderExpression(children[1])[0]), "unknown1"} + expression, _ := renderExpression(ast, children[0]) + index, _ := renderExpression(ast, children[1]) + src := fmt.Sprintf("%s[%s]", expression, index) + return src, "unknown1" } diff --git a/asm_label_attr.go b/ast/asm_label_attr.go similarity index 82% rename from asm_label_attr.go rename to ast/asm_label_attr.go index ce50a59e5..b121f89f1 100644 --- a/asm_label_attr.go +++ b/ast/asm_label_attr.go @@ -1,4 +1,4 @@ -package main +package ast type AsmLabelAttr struct { Address string @@ -20,3 +20,7 @@ func parseAsmLabelAttr(line string) *AsmLabelAttr { Children: []interface{}{}, } } + +func (n *AsmLabelAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/ast/ast.go b/ast/ast.go new file mode 100644 index 000000000..3c99dd129 --- /dev/null +++ b/ast/ast.go @@ -0,0 +1,196 @@ +package ast + +import ( + "regexp" + "strings" +) + +type Ast struct { + imports []string + + // for rendering go src + functionName string + indent int + returnType string +} + +func NewAst() *Ast { + return &Ast{ + imports: []string{"fmt"}, + } +} + +func (a *Ast) Imports() []string { + return a.imports +} + +func (a *Ast) addImport(name string) { + for _, i := range a.imports { + if i == name { + // already imported + return + } + } + + a.imports = append(a.imports, name) +} + +func (a *Ast) importType(name string) string { + if strings.Index(name, ".") != -1 { + parts := strings.Split(name, ".") + a.addImport(strings.Join(parts[:len(parts)-1], ".")) + + parts2 := strings.Split(name, "/") + return parts2[len(parts2)-1] + } + + return name +} + +type Node interface { + render(ast *Ast) (string, string) +} + +func Parse(line string) Node { + + nodeName := strings.SplitN(line, " ", 2)[0] + + switch nodeName { + case "AlwaysInlineAttr": + return parseAlwaysInlineAttr(line) + case "ArraySubscriptExpr": + return parseArraySubscriptExpr(line) + case "AsmLabelAttr": + return parseAsmLabelAttr(line) + case "AvailabilityAttr": + return parseAvailabilityAttr(line) + case "BinaryOperator": + return parseBinaryOperator(line) + case "BreakStmt": + return parseBreakStmt(line) + case "BuiltinType": + return parseBuiltinType(line) + case "CallExpr": + return parseCallExpr(line) + case "CharacterLiteral": + return parseCharacterLiteral(line) + case "CompoundStmt": + return parseCompoundStmt(line) + case "ConditionalOperator": + return parseConditionalOperator(line) + case "ConstAttr": + return parseConstAttr(line) + case "ConstantArrayType": + return parseConstantArrayType(line) + case "CStyleCastExpr": + return parseCStyleCastExpr(line) + case "DeclRefExpr": + return parseDeclRefExpr(line) + case "DeclStmt": + return parseDeclStmt(line) + case "DeprecatedAttr": + return parseDeprecatedAttr(line) + case "ElaboratedType": + return parseElaboratedType(line) + case "Enum": + return parseEnum(line) + case "EnumConstantDecl": + return parseEnumConstantDecl(line) + case "EnumDecl": + return parseEnumDecl(line) + case "EnumType": + return parseEnumType(line) + case "FieldDecl": + return parseFieldDecl(line) + case "FloatingLiteral": + return parseFloatingLiteral(line) + case "FormatAttr": + return parseFormatAttr(line) + case "FunctionDecl": + return parseFunctionDecl(line) + case "FunctionProtoType": + return parseFunctionProtoType(line) + case "ForStmt": + return parseForStmt(line) + case "IfStmt": + return parseIfStmt(line) + case "ImplicitCastExpr": + return parseImplicitCastExpr(line) + case "IntegerLiteral": + return parseIntegerLiteral(line) + case "MallocAttr": + return parseMallocAttr(line) + case "MemberExpr": + return parseMemberExpr(line) + case "ModeAttr": + return parseModeAttr(line) + case "NoThrowAttr": + return parseNoThrowAttr(line) + case "NonNullAttr": + return parseNonNullAttr(line) + case "ParenExpr": + return parseParenExpr(line) + case "ParmVarDecl": + return parseParmVarDecl(line) + case "PointerType": + return parsePointerType(line) + case "PredefinedExpr": + return parsePredefinedExpr(line) + case "QualType": + return parseQualType(line) + case "Record": + return parseRecord(line) + case "RecordDecl": + return parseRecordDecl(line) + case "RecordType": + return parseRecordType(line) + case "RestrictAttr": + return parseRestrictAttr(line) + case "ReturnStmt": + return parseReturnStmt(line) + case "StringLiteral": + return parseStringLiteral(line) + case "TranslationUnitDecl": + return parseTranslationUnitDecl(line) + case "Typedef": + return parseTypedef(line) + case "TypedefDecl": + return parseTypedefDecl(line) + case "TypedefType": + return parseTypedefType(line) + case "UnaryOperator": + return parseUnaryOperator(line) + case "VarDecl": + return parseVarDecl(line) + case "WhileStmt": + return parseWhileStmt(line) + case "NullStmt": + return nil + default: + panic("Unknown node type: '" + line + "'") + } +} + +func groupsFromRegex(rx, line string) map[string]string { + // We remove tabs and newlines from the regex. This is purely cosmetic, + // as the regex input can be quite long and it's nice for the caller to + // be able to format it in a more readable way. + fullRegexp := "(?P
[0-9a-fx]+) " + + strings.Replace(strings.Replace(rx, "\n", "", -1), "\t", "", -1) + re := regexp.MustCompile(fullRegexp) + + match := re.FindStringSubmatch(line) + if len(match) == 0 { + panic("could not match regexp '" + fullRegexp + + "' with string '" + line + "'") + } + + result := make(map[string]string) + for i, name := range re.SubexpNames() { + if i != 0 { + result[name] = match[i] + } + } + + return result +} diff --git a/ast_test.go b/ast/ast_test.go similarity index 99% rename from ast_test.go rename to ast/ast_test.go index 4a408c541..b59de617d 100644 --- a/ast_test.go +++ b/ast/ast_test.go @@ -1,4 +1,4 @@ -package main +package ast import ( "reflect" diff --git a/availability_attr.go b/ast/availability_attr.go similarity index 91% rename from availability_attr.go rename to ast/availability_attr.go index 0b568cc12..0a7865fb9 100644 --- a/availability_attr.go +++ b/ast/availability_attr.go @@ -1,4 +1,4 @@ -package main +package ast type AvailabilityAttr struct { Address string @@ -39,3 +39,7 @@ func parseAvailabilityAttr(line string) *AvailabilityAttr { Children: []interface{}{}, } } + +func (n *AvailabilityAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/binary_operator.go b/ast/binary_operator.go similarity index 55% rename from binary_operator.go rename to ast/binary_operator.go index 8ea831d3a..06ff2cc64 100644 --- a/binary_operator.go +++ b/ast/binary_operator.go @@ -1,4 +1,4 @@ -package main +package ast import "fmt" @@ -7,7 +7,7 @@ type BinaryOperator struct { Position string Type string Operator string - Children []interface{} + Children []Node } func parseBinaryOperator(line string) *BinaryOperator { @@ -21,30 +21,31 @@ func parseBinaryOperator(line string) *BinaryOperator { Position: groups["position"], Type: groups["type"], Operator: groups["operator"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *BinaryOperator) Render() []string { +func (n *BinaryOperator) render(ast *Ast) (string, string) { operator := n.Operator - left := renderExpression(n.Children[0]) - right := renderExpression(n.Children[1]) + left, leftType := renderExpression(ast, n.Children[0]) + right, rightType := renderExpression(ast, n.Children[1]) return_type := "bool" if inStrings(operator, []string{"|", "&", "+", "-", "*", "/"}) { // TODO: The left and right type might be different - return_type = left[1] + return_type = leftType } if operator == "&&" { - left[0] = cast(left[0], left[1], return_type) - right[0] = cast(right[0], right[1], return_type) + left = cast(ast, left, leftType, return_type) + right = cast(ast, right, rightType, return_type) } - if (operator == "!=" || operator == "==") && right[0] == "(0)" { - right[0] = "nil" + if (operator == "!=" || operator == "==") && right == "(0)" { + right = "nil" } - return []string{fmt.Sprintf("%s %s %s", left[0], operator, right[0]), return_type} + src := fmt.Sprintf("%s %s %s", left, operator, right) + return src, return_type } diff --git a/break_stmt.go b/ast/break_stmt.go similarity index 78% rename from break_stmt.go rename to ast/break_stmt.go index 78954dd17..426192e36 100644 --- a/break_stmt.go +++ b/ast/break_stmt.go @@ -1,4 +1,4 @@ -package main +package ast type BreakStmt struct { Address string @@ -19,6 +19,6 @@ func parseBreakStmt(line string) *BreakStmt { } } -func (n *BreakStmt) Render() []string { - return []string{"break", ""} +func (n *BreakStmt) render(ast *Ast) (string, string) { + return "break", "" } diff --git a/builtin_type.go b/ast/builtin_type.go similarity index 78% rename from builtin_type.go rename to ast/builtin_type.go index 445076185..4f845aeac 100644 --- a/builtin_type.go +++ b/ast/builtin_type.go @@ -1,4 +1,4 @@ -package main +package ast type BuiltinType struct { Address string @@ -18,3 +18,7 @@ func parseBuiltinType(line string) *BuiltinType { Children: []interface{}{}, } } + +func (n *BuiltinType) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/c_style_cast_expr.go b/ast/c_style_cast_expr.go similarity index 73% rename from c_style_cast_expr.go rename to ast/c_style_cast_expr.go index d1994069d..8c10d30bf 100644 --- a/c_style_cast_expr.go +++ b/ast/c_style_cast_expr.go @@ -1,11 +1,11 @@ -package main +package ast type CStyleCastExpr struct { Address string Position string Type string Kind string - Children []interface{} + Children []Node } func parseCStyleCastExpr(line string) *CStyleCastExpr { @@ -19,11 +19,11 @@ func parseCStyleCastExpr(line string) *CStyleCastExpr { Position: groups["position"], Type: groups["type"], Kind: groups["kind"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *CStyleCastExpr) Render() []string { +func (n *CStyleCastExpr) render(ast *Ast) (string, string) { children := n.Children - return renderExpression(children[0]) + return renderExpression(ast, children[0]) } diff --git a/call_expr.go b/ast/call_expr.go similarity index 66% rename from call_expr.go rename to ast/call_expr.go index 7d80d5ac3..11fa33692 100644 --- a/call_expr.go +++ b/ast/call_expr.go @@ -1,4 +1,4 @@ -package main +package ast import ( "fmt" @@ -9,7 +9,7 @@ type CallExpr struct { Address string Position string Type string - Children []interface{} + Children []Node } func parseCallExpr(line string) *CallExpr { @@ -22,19 +22,19 @@ func parseCallExpr(line string) *CallExpr { Address: groups["address"], Position: groups["position"], Type: groups["type"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *CallExpr) Render() []string { +func (n *CallExpr) render(ast *Ast) (string, string) { children := n.Children - func_name := renderExpression(children[0])[0] + func_name, _ := renderExpression(ast, children[0]) func_def := getFunctionDefinition(func_name) if func_def.Substitution != "" { parts := strings.Split(func_def.Substitution, ".") - addImport(strings.Join(parts[:len(parts)-1], ".")) + ast.addImport(strings.Join(parts[:len(parts)-1], ".")) parts2 := strings.Split(func_def.Substitution, "/") func_name = parts2[len(parts2)-1] @@ -43,18 +43,18 @@ func (n *CallExpr) Render() []string { args := []string{} i := 0 for _, arg := range children[1:] { - e := renderExpression(arg) + e, eType := renderExpression(ast, arg) if i > len(func_def.ArgumentTypes)-1 { // This means the argument is one of the varargs // so we don't know what type it needs to be // cast to. - args = append(args, e[0]) + args = append(args, e) } else { - args = append(args, cast(e[0], e[1], func_def.ArgumentTypes[i])) + args = append(args, cast(ast, e, eType, func_def.ArgumentTypes[i])) } - i += 1 + i++ } parts := []string{} @@ -63,7 +63,6 @@ func (n *CallExpr) Render() []string { parts = append(parts, v) } - return []string{ - fmt.Sprintf("%s(%s)", func_name, strings.Join(parts, ", ")), - func_def.ReturnType} + src := fmt.Sprintf("%s(%s)", func_name, strings.Join(parts, ", ")) + return src, func_def.ReturnType } diff --git a/cast.go b/ast/cast.go similarity index 73% rename from cast.go rename to ast/cast.go index 0e3e24986..bb21f942c 100644 --- a/cast.go +++ b/ast/cast.go @@ -1,10 +1,10 @@ -package main +package ast import "fmt" -func cast(expr, fromType, toType string) string { - fromType = resolveType(fromType) - toType = resolveType(toType) +func cast(ast *Ast, expr, fromType, toType string) string { + fromType = resolveType(ast, fromType) + toType = resolveType(ast, toType) if fromType == toType { return expr @@ -27,6 +27,6 @@ func cast(expr, fromType, toType string) string { return fmt.Sprintf("%s(%s)", toType, expr) } - addImport("github.com/elliotchance/c2go/noarch") + ast.addImport("github.com/elliotchance/c2go/noarch") return fmt.Sprintf("noarch.%sTo%s(%s)", ucfirst(fromType), ucfirst(toType), expr) } diff --git a/character_literal.go b/ast/character_literal.go similarity index 83% rename from character_literal.go rename to ast/character_literal.go index 9d0897a3a..a5236c88c 100644 --- a/character_literal.go +++ b/ast/character_literal.go @@ -1,4 +1,4 @@ -package main +package ast type CharacterLiteral struct { Address string @@ -22,3 +22,7 @@ func parseCharacterLiteral(line string) *CharacterLiteral { Children: []interface{}{}, } } + +func (n *CharacterLiteral) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/common.go b/ast/common.go similarity index 61% rename from common.go rename to ast/common.go index 1108e2a5d..39231e2bc 100644 --- a/common.go +++ b/ast/common.go @@ -1,4 +1,4 @@ -package main +package ast import ( "bytes" @@ -10,16 +10,17 @@ func printLine(out *bytes.Buffer, line string, indent int) { out.WriteString(fmt.Sprintf("%s%s\n", strings.Repeat("\t", indent), line)) } -func renderExpression(node interface{}) []string { - if node == nil { - return []string{"", "unknown54"} - } +func Render(ast *Ast, node Node) string { + src, _ := node.render(ast) + return src +} - if n, ok := node.(ExpressionRenderer); ok { - return n.Render() +func renderExpression(ast *Ast, node Node) (string, string) { + if node == nil { + return "", "unknown54" } - panic(fmt.Sprintf("renderExpression: %#v", node)) + return node.render(ast) } func getFunctionParams(f *FunctionDecl) []*ParmVarDecl { @@ -47,11 +48,11 @@ func getFunctionReturnType(f string) string { return strings.TrimSpace(strings.Split(f, "(")[0]) } -func Render(out *bytes.Buffer, node interface{}, functionName string, indent int, returnType string) { - if n, ok := node.(LineRenderer); ok { - n.RenderLine(out, functionName, indent, returnType) - return - } +// func Render(out *bytes.Buffer, node interface{}, functionName string, indent int, returnType string) { +// if n, ok := node.(LineRenderer); ok { +// n.RenderLine(out, functionName, indent, returnType) +// return +// } - printLine(out, renderExpression(node)[0], indent) -} +// printLine(out, renderExpression(node)[0], indent) +// } diff --git a/compound_stmt.go b/ast/compound_stmt.go similarity index 63% rename from compound_stmt.go rename to ast/compound_stmt.go index 067c9d5ab..09a872fa5 100644 --- a/compound_stmt.go +++ b/ast/compound_stmt.go @@ -1,11 +1,11 @@ -package main +package ast import "bytes" type CompoundStmt struct { Address string Position string - Children []interface{} + Children []Node } func parseCompoundStmt(line string) *CompoundStmt { @@ -17,12 +17,21 @@ func parseCompoundStmt(line string) *CompoundStmt { return &CompoundStmt{ Address: groups["address"], Position: groups["position"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *CompoundStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { +func (n *CompoundStmt) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) + for _, c := range n.Children { - Render(out, c, functionName, indent, returnType) + src, _ := renderExpression(ast, c) + printLine(out, src, ast.indent) } + + return out.String(), "" +} + +func (n *CompoundStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { + } diff --git a/ast/conditional_operator.go b/ast/conditional_operator.go new file mode 100644 index 000000000..1f31de5dd --- /dev/null +++ b/ast/conditional_operator.go @@ -0,0 +1,34 @@ +package ast + +import "fmt" + +type ConditionalOperator struct { + Address string + Position string + Type string + Children []Node +} + +func parseConditionalOperator(line string) *ConditionalOperator { + groups := groupsFromRegex( + `<(?P.*)> '(?P.*?)'`, + line, + ) + + return &ConditionalOperator{ + Address: groups["address"], + Position: groups["position"], + Type: groups["type"], + Children: []Node{}, + } +} + +func (n *ConditionalOperator) render(ast *Ast) (string, string) { + a, _ := renderExpression(ast, n.Children[0]) + b, _ := renderExpression(ast, n.Children[1]) + c, _ := renderExpression(ast, n.Children[2]) + + ast.addImport("github.com/elliotchance/c2go/noarch") + src := fmt.Sprintf("noarch.Ternary(%s, func () interface{} { return %s }, func () interface{} { return %s })", a, b, c) + return src, n.Type +} diff --git a/const_attr.go b/ast/const_attr.go similarity index 81% rename from const_attr.go rename to ast/const_attr.go index 8e2fb3a22..09129ab40 100644 --- a/const_attr.go +++ b/ast/const_attr.go @@ -1,4 +1,4 @@ -package main +package ast type ConstAttr struct { Address string @@ -20,3 +20,7 @@ func parseConstAttr(line string) *ConstAttr { Children: []interface{}{}, } } + +func (n *ConstAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/constant_array_type.go b/ast/constant_array_type.go similarity index 72% rename from constant_array_type.go rename to ast/constant_array_type.go index 4f8e6e4f3..24486af98 100644 --- a/constant_array_type.go +++ b/ast/constant_array_type.go @@ -1,10 +1,10 @@ -package main +package ast type ConstantArrayType struct { Address string Type string Size int - Children []interface{} + Children []Node } func parseConstantArrayType(line string) *ConstantArrayType { @@ -17,6 +17,10 @@ func parseConstantArrayType(line string) *ConstantArrayType { Address: groups["address"], Type: groups["type"], Size: atoi(groups["size"]), - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *ConstantArrayType) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/decl_ref_expr.go b/ast/decl_ref_expr.go similarity index 86% rename from decl_ref_expr.go rename to ast/decl_ref_expr.go index 3488f78a6..b99ace329 100644 --- a/decl_ref_expr.go +++ b/ast/decl_ref_expr.go @@ -1,4 +1,4 @@ -package main +package ast type DeclRefExpr struct { Address string @@ -38,16 +38,16 @@ func parseDeclRefExpr(line string) *DeclRefExpr { } } -func (n *DeclRefExpr) Render() []string { +func (n *DeclRefExpr) render(ast *Ast) (string, string) { name := n.Name if name == "argc" { name = "len(os.Args)" - addImport("os") + ast.addImport("os") } else if name == "argv" { name = "os.Args" - addImport("os") + ast.addImport("os") } - return []string{name, n.Type} + return name, n.Type } diff --git a/decl_stmt.go b/ast/decl_stmt.go similarity index 56% rename from decl_stmt.go rename to ast/decl_stmt.go index 8fcac6fcf..b7e24fe0b 100644 --- a/decl_stmt.go +++ b/ast/decl_stmt.go @@ -1,11 +1,11 @@ -package main +package ast import "bytes" type DeclStmt struct { Address string Position string - Children []interface{} + Children []Node } func parseDeclStmt(line string) *DeclStmt { @@ -17,12 +17,17 @@ func parseDeclStmt(line string) *DeclStmt { return &DeclStmt{ Address: groups["address"], Position: groups["position"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *DeclStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { +func (n *DeclStmt) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) + for _, child := range n.Children { - printLine(out, renderExpression(child)[0], indent) + src, _ := renderExpression(ast, child) + printLine(out, src, ast.indent) } + + return out.String(), "" } diff --git a/deprecated_attr.go b/ast/deprecated_attr.go similarity index 84% rename from deprecated_attr.go rename to ast/deprecated_attr.go index c280a159f..70aafe0ab 100644 --- a/deprecated_attr.go +++ b/ast/deprecated_attr.go @@ -1,4 +1,4 @@ -package main +package ast type DeprecatedAttr struct { Address string @@ -22,3 +22,7 @@ func parseDeprecatedAttr(line string) *DeprecatedAttr { Children: []interface{}{}, } } + +func (n *DeprecatedAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/elaborated_type.go b/ast/elaborated_type.go similarity index 71% rename from elaborated_type.go rename to ast/elaborated_type.go index 1d88f5dd7..58e623b08 100644 --- a/elaborated_type.go +++ b/ast/elaborated_type.go @@ -1,10 +1,10 @@ -package main +package ast type ElaboratedType struct { Address string Type string Tags string - Children []interface{} + Children []Node } func parseElaboratedType(line string) *ElaboratedType { @@ -17,6 +17,10 @@ func parseElaboratedType(line string) *ElaboratedType { Address: groups["address"], Type: groups["type"], Tags: groups["tags"], - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *ElaboratedType) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/enum.go b/ast/enum.go similarity index 77% rename from enum.go rename to ast/enum.go index 48d5fbe81..a8917b8c9 100644 --- a/enum.go +++ b/ast/enum.go @@ -1,4 +1,4 @@ -package main +package ast type Enum struct { Address string @@ -18,3 +18,7 @@ func parseEnum(line string) *Enum { Children: []interface{}{}, } } + +func (n *Enum) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/enum_constant_decl.go b/ast/enum_constant_decl.go similarity index 78% rename from enum_constant_decl.go rename to ast/enum_constant_decl.go index fbcb9a1ec..dcdda7cd4 100644 --- a/enum_constant_decl.go +++ b/ast/enum_constant_decl.go @@ -1,4 +1,4 @@ -package main +package ast type EnumConstantDecl struct { Address string @@ -6,7 +6,7 @@ type EnumConstantDecl struct { Position2 string Name string Type string - Children []interface{} + Children []Node } func parseEnumConstantDecl(line string) *EnumConstantDecl { @@ -24,6 +24,10 @@ func parseEnumConstantDecl(line string) *EnumConstantDecl { Position2: groups["position2"], Name: groups["name"], Type: groups["type"], - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *EnumConstantDecl) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/enum_decl.go b/ast/enum_decl.go similarity index 76% rename from enum_decl.go rename to ast/enum_decl.go index c0ef40a0b..e23fb5efc 100644 --- a/enum_decl.go +++ b/ast/enum_decl.go @@ -1,4 +1,4 @@ -package main +package ast import "strings" @@ -7,7 +7,7 @@ type EnumDecl struct { Position string Position2 string Name string - Children []interface{} + Children []Node } func parseEnumDecl(line string) *EnumDecl { @@ -21,10 +21,10 @@ func parseEnumDecl(line string) *EnumDecl { Position: groups["position"], Position2: groups["position2"], Name: strings.TrimSpace(groups["name"]), - Children: []interface{}{}, + Children: []Node{}, } } -func (n *EnumDecl) Render() []string { - return []string{"", ""} +func (n *EnumDecl) render(ast *Ast) (string, string) { + return "", "" } diff --git a/enum_type.go b/ast/enum_type.go similarity index 66% rename from enum_type.go rename to ast/enum_type.go index 01c5fa8c7..194cc35e8 100644 --- a/enum_type.go +++ b/ast/enum_type.go @@ -1,9 +1,9 @@ -package main +package ast type EnumType struct { Address string Name string - Children []interface{} + Children []Node } func parseEnumType(line string) *EnumType { @@ -15,6 +15,10 @@ func parseEnumType(line string) *EnumType { return &EnumType{ Address: groups["address"], Name: groups["name"], - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *EnumType) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/field_decl.go b/ast/field_decl.go similarity index 79% rename from field_decl.go rename to ast/field_decl.go index d8e40e343..4dc79ffc3 100644 --- a/field_decl.go +++ b/ast/field_decl.go @@ -1,4 +1,4 @@ -package main +package ast import ( "fmt" @@ -12,7 +12,7 @@ type FieldDecl struct { Name string Type string Referenced bool - Children []interface{} + Children []Node } func parseFieldDecl(line string) *FieldDecl { @@ -32,12 +32,12 @@ func parseFieldDecl(line string) *FieldDecl { Name: strings.TrimSpace(groups["name"]), Type: groups["type"], Referenced: len(groups["referenced"]) > 0, - Children: []interface{}{}, + Children: []Node{}, } } -func (n *FieldDecl) Render() []string { - fieldType := resolveType(n.Type) +func (n *FieldDecl) render(ast *Ast) (string, string) { + fieldType := resolveType(ast, n.Type) name := n.Name //if name == "" { @@ -53,7 +53,8 @@ func (n *FieldDecl) Render() []string { // It may have a default value. suffix := "" if len(n.Children) > 0 { - suffix = fmt.Sprintf(" = %s", renderExpression(n.Children[0])[0]) + src, _ := renderExpression(ast, n.Children[0]) + suffix = fmt.Sprintf(" = %s", src) } // NULL is a macro that one rendered looks like "(0)" we have to be @@ -63,5 +64,6 @@ func (n *FieldDecl) Render() []string { suffix = " = nil" } - return []string{fmt.Sprintf("%s %s%s", name, fieldType, suffix), "unknown3"} + src := fmt.Sprintf("%s %s%s", name, fieldType, suffix) + return src, "unknown3" } diff --git a/floating_literal.go b/ast/floating_literal.go similarity index 80% rename from floating_literal.go rename to ast/floating_literal.go index db3b95acf..59b31e0c8 100644 --- a/floating_literal.go +++ b/ast/floating_literal.go @@ -1,4 +1,4 @@ -package main +package ast import "fmt" @@ -25,6 +25,6 @@ func parseFloatingLiteral(line string) *FloatingLiteral { } } -func (n *FloatingLiteral) Render() []string { - return []string{fmt.Sprintf("%f", n.Value), "double"} +func (n *FloatingLiteral) render(ast *Ast) (string, string) { + return fmt.Sprintf("%f", n.Value), "double" } diff --git a/for_stmt.go b/ast/for_stmt.go similarity index 69% rename from for_stmt.go rename to ast/for_stmt.go index e5b266481..c8ca8618a 100644 --- a/for_stmt.go +++ b/ast/for_stmt.go @@ -1,4 +1,4 @@ -package main +package ast import ( "bytes" @@ -8,7 +8,7 @@ import ( type ForStmt struct { Address string Position string - Children []interface{} + Children []Node } func parseForStmt(line string) *ForStmt { @@ -20,11 +20,13 @@ func parseForStmt(line string) *ForStmt { return &ForStmt{ Address: groups["address"], Position: groups["position"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *ForStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { +func (n *ForStmt) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) + children := n.Children // There are always 5 children in a ForStmt, for example: @@ -50,19 +52,20 @@ func (n *ForStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, panic("non-nil child 1 in ForStmt") } - init := renderExpression(children[0])[0] - conditional := renderExpression(children[2])[0] - step := renderExpression(children[3])[0] - body := children[4] + init, _ := renderExpression(ast, children[0]) + conditional, _ := renderExpression(ast, children[2]) + step, _ := renderExpression(ast, children[3]) + body, _ := renderExpression(ast, children[4]) if init == "" && conditional == "" && step == "" { - printLine(out, "for {", indent) + printLine(out, "for {", ast.indent) } else { printLine(out, fmt.Sprintf("for %s; %s; %s {", - init, conditional, step), indent) + init, conditional, step), ast.indent) } - Render(out, body, functionName, indent+1, returnType) + printLine(out, body, ast.indent+1) + printLine(out, "}", ast.indent) - printLine(out, "}", indent) + return out.String(), "" } diff --git a/format_attr.go b/ast/format_attr.go similarity index 89% rename from format_attr.go rename to ast/format_attr.go index 5f9b8c6c2..220a21ef4 100644 --- a/format_attr.go +++ b/ast/format_attr.go @@ -1,4 +1,4 @@ -package main +package ast type FormatAttr struct { Address string @@ -33,3 +33,7 @@ func parseFormatAttr(line string) *FormatAttr { Children: []interface{}{}, } } + +func (n *FormatAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/function_decl.go b/ast/function_decl.go similarity index 65% rename from function_decl.go rename to ast/function_decl.go index b66a821af..3f79e94b8 100644 --- a/function_decl.go +++ b/ast/function_decl.go @@ -1,4 +1,4 @@ -package main +package ast import ( "bytes" @@ -16,7 +16,7 @@ type FunctionDecl struct { IsExtern bool IsImplicit bool IsUsed bool - Children []interface{} + Children []Node } func parseFunctionDecl(line string) *FunctionDecl { @@ -47,54 +47,58 @@ func parseFunctionDecl(line string) *FunctionDecl { IsExtern: len(groups["extern"]) > 0, IsImplicit: len(groups["implicit"]) > 0, IsUsed: len(groups["used"]) > 0, - Children: []interface{}{}, + Children: []Node{}, } } -func (n *FunctionDecl) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { - functionName = strings.TrimSpace(n.Name) +func (n *FunctionDecl) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) - if functionName == "__istype" || functionName == "__isctype" || - functionName == "__wcwidth" || functionName == "__sputc" || - functionName == "__inline_signbitf" || - functionName == "__inline_signbitd" || - functionName == "__inline_signbitl" { - return + ast.functionName = strings.TrimSpace(n.Name) + + if ast.functionName == "__istype" || + ast.functionName == "__isctype" || + ast.functionName == "__wcwidth" || + ast.functionName == "__sputc" || + ast.functionName == "__inline_signbitf" || + ast.functionName == "__inline_signbitd" || + ast.functionName == "__inline_signbitl" { + return "", "" } - has_body := false + hasBody := false if len(n.Children) > 0 { for _, c := range n.Children { if _, ok := c.(*CompoundStmt); ok { - has_body = true + hasBody = true } } } args := []string{} for _, a := range getFunctionParams(n) { - args = append(args, fmt.Sprintf("%s %s", a.Name, resolveType(a.Type))) + args = append(args, fmt.Sprintf("%s %s", a.Name, resolveType(ast, a.Type))) } - if has_body { + if hasBody { returnType := getFunctionReturnType(n.Type) - if functionName == "main" { - printLine(out, "func main() {", indent) + if ast.functionName == "main" { + printLine(out, "func main() {", ast.indent) } else { printLine(out, fmt.Sprintf("func %s(%s) %s {", - functionName, strings.Join(args, ", "), - resolveType(returnType)), indent) + ast.functionName, strings.Join(args, ", "), + resolveType(ast, returnType)), ast.indent) } for _, c := range n.Children { if _, ok := c.(*CompoundStmt); ok { - Render(out, c, functionName, - indent+1, n.Type) + src, _ := renderExpression(ast, c) + printLine(out, src, ast.indent+1) } } - printLine(out, "}\n", indent) + printLine(out, "}\n", ast.indent) params := []string{} for _, v := range getFunctionParams(n) { @@ -107,4 +111,6 @@ func (n *FunctionDecl) RenderLine(out *bytes.Buffer, functionName string, indent ArgumentTypes: params, }) } + + return out.String(), "" } diff --git a/function_definition.go b/ast/function_definition.go similarity index 99% rename from function_definition.go rename to ast/function_definition.go index 5cf0d56b5..a33598efc 100644 --- a/function_definition.go +++ b/ast/function_definition.go @@ -1,4 +1,4 @@ -package main +package ast import ( "regexp" diff --git a/function_proto_type.go b/ast/function_proto_type.go similarity index 72% rename from function_proto_type.go rename to ast/function_proto_type.go index 79dc311ee..de70606f6 100644 --- a/function_proto_type.go +++ b/ast/function_proto_type.go @@ -1,10 +1,10 @@ -package main +package ast type FunctionProtoType struct { Address string Type string Kind string - Children []interface{} + Children []Node } func parseFunctionProtoType(line string) *FunctionProtoType { @@ -17,6 +17,10 @@ func parseFunctionProtoType(line string) *FunctionProtoType { Address: groups["address"], Type: groups["type"], Kind: groups["kind"], - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *FunctionProtoType) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/if_stmt.go b/ast/if_stmt.go similarity index 70% rename from if_stmt.go rename to ast/if_stmt.go index 9a986038d..93e7a1bdf 100644 --- a/if_stmt.go +++ b/ast/if_stmt.go @@ -1,4 +1,4 @@ -package main +package ast import ( "bytes" @@ -8,7 +8,7 @@ import ( type IfStmt struct { Address string Position string - Children []interface{} + Children []Node } func parseIfStmt(line string) *IfStmt { @@ -20,11 +20,12 @@ func parseIfStmt(line string) *IfStmt { return &IfStmt{ Address: groups["address"], Position: groups["position"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *IfStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { +func (n *IfStmt) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) children := n.Children // There is always 4 or 5 children in an IfStmt. For example: @@ -64,19 +65,22 @@ func (n *IfStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, panic("non-nil child 0 in ForStmt") } - conditional := renderExpression(children[1]) + conditional, conditionalType := renderExpression(ast, children[1]) // The condition in Go must always be a bool. - boolCondition := cast(conditional[0], conditional[1], "bool") + boolCondition := cast(ast, conditional, conditionalType, "bool") - printLine(out, fmt.Sprintf("if %s {", boolCondition), indent) - - Render(out, children[2], functionName, indent+1, returnType) + printLine(out, fmt.Sprintf("if %s {", boolCondition), ast.indent) + body, _ := renderExpression(ast, children[2]) + printLine(out, body, ast.indent+1) if children[3] != nil { - printLine(out, "} else {", indent) - Render(out, children[3], functionName, indent+1, returnType) + printLine(out, "} else {", ast.indent) + body, _ := renderExpression(ast, children[3]) + printLine(out, body, ast.indent+1) } - printLine(out, "}", indent) + printLine(out, "}", ast.indent) + + return out.String(), "" } diff --git a/implicit_cast_expr.go b/ast/implicit_cast_expr.go similarity index 72% rename from implicit_cast_expr.go rename to ast/implicit_cast_expr.go index a352f1898..1fdc6e725 100644 --- a/implicit_cast_expr.go +++ b/ast/implicit_cast_expr.go @@ -1,11 +1,11 @@ -package main +package ast type ImplicitCastExpr struct { Address string Position string Type string Kind string - Children []interface{} + Children []Node } func parseImplicitCastExpr(line string) *ImplicitCastExpr { @@ -19,10 +19,10 @@ func parseImplicitCastExpr(line string) *ImplicitCastExpr { Position: groups["position"], Type: groups["type"], Kind: groups["kind"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *ImplicitCastExpr) Render() []string { - return renderExpression(n.Children[0]) +func (n *ImplicitCastExpr) render(ast *Ast) (string, string) { + return renderExpression(ast, n.Children[0]) } diff --git a/integer_literal.go b/ast/integer_literal.go similarity index 82% rename from integer_literal.go rename to ast/integer_literal.go index bee1d6c67..577630e2b 100644 --- a/integer_literal.go +++ b/ast/integer_literal.go @@ -1,4 +1,4 @@ -package main +package ast import "strconv" @@ -25,12 +25,12 @@ func parseIntegerLiteral(line string) *IntegerLiteral { } } -func (n *IntegerLiteral) Render() []string { +func (n *IntegerLiteral) render(ast *Ast) (string, string) { literal := n.Value // FIXME //if str(literal)[-1] == 'L': // literal = '%s(%s)' % (resolveType('long'), literal[:-1]) - return []string{strconv.FormatInt(int64(literal), 10), "int"} + return strconv.FormatInt(int64(literal), 10), "int" } diff --git a/malloc_attr.go b/ast/malloc_attr.go similarity index 78% rename from malloc_attr.go rename to ast/malloc_attr.go index 0fa9a5998..b9a3afaa1 100644 --- a/malloc_attr.go +++ b/ast/malloc_attr.go @@ -1,4 +1,4 @@ -package main +package ast type MallocAttr struct { Address string @@ -18,3 +18,7 @@ func parseMallocAttr(line string) *MallocAttr { Children: []interface{}{}, } } + +func (n *MallocAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/member_expr.go b/ast/member_expr.go similarity index 62% rename from member_expr.go rename to ast/member_expr.go index 85eafcf52..239d421b0 100644 --- a/member_expr.go +++ b/ast/member_expr.go @@ -1,4 +1,4 @@ -package main +package ast import "fmt" @@ -9,7 +9,7 @@ type MemberExpr struct { Lvalue bool Name string Address2 string - Children []interface{} + Children []Node } func parseMemberExpr(line string) *MemberExpr { @@ -29,23 +29,21 @@ func parseMemberExpr(line string) *MemberExpr { Lvalue: true, Name: groups["name"], Address2: groups["address2"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *MemberExpr) Render() []string { +func (n *MemberExpr) render(ast *Ast) (string, string) { children := n.Children - lhs := renderExpression(children[0]) - lhs_type := resolveType(lhs[1]) + lhs, lhsType := renderExpression(ast, children[0]) + lhsResolvedType := resolveType(ast, lhsType) rhs := n.Name - if inStrings(lhs_type, []string{"darwin.Float2", "darwin.Double2"}) { + if inStrings(lhsResolvedType, []string{"darwin.Float2", "darwin.Double2"}) { rhs = getExportedName(rhs) } - return []string{ - fmt.Sprintf("%s.%s", lhs[0], rhs), - children[0].(*DeclRefExpr).Type, - } + src := fmt.Sprintf("%s.%s", lhs, rhs) + return src, children[0].(*DeclRefExpr).Type } diff --git a/mode_attr.go b/ast/mode_attr.go similarity index 81% rename from mode_attr.go rename to ast/mode_attr.go index 35183fe82..48ac36178 100644 --- a/mode_attr.go +++ b/ast/mode_attr.go @@ -1,4 +1,4 @@ -package main +package ast type ModeAttr struct { Address string @@ -20,3 +20,7 @@ func parseModeAttr(line string) *ModeAttr { Children: []interface{}{}, } } + +func (n *ModeAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/no_throw_attr.go b/ast/no_throw_attr.go similarity index 78% rename from no_throw_attr.go rename to ast/no_throw_attr.go index 826838534..644035d0f 100644 --- a/no_throw_attr.go +++ b/ast/no_throw_attr.go @@ -1,4 +1,4 @@ -package main +package ast type NoThrowAttr struct { Address string @@ -18,3 +18,7 @@ func parseNoThrowAttr(line string) *NoThrowAttr { Children: []interface{}{}, } } + +func (n *NoThrowAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/non_null_attr.go b/ast/non_null_attr.go similarity index 78% rename from non_null_attr.go rename to ast/non_null_attr.go index f5c7e8e37..2bfa9cfc0 100644 --- a/non_null_attr.go +++ b/ast/non_null_attr.go @@ -1,4 +1,4 @@ -package main +package ast type NonNullAttr struct { Address string @@ -18,3 +18,7 @@ func parseNonNullAttr(line string) *NonNullAttr { Children: []interface{}{}, } } + +func (n *NonNullAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/paren_expr.go b/ast/paren_expr.go similarity index 62% rename from paren_expr.go rename to ast/paren_expr.go index 692464cc7..985653faa 100644 --- a/paren_expr.go +++ b/ast/paren_expr.go @@ -1,4 +1,4 @@ -package main +package ast import "fmt" @@ -6,7 +6,7 @@ type ParenExpr struct { Address string Position string Type string - Children []interface{} + Children []Node } func parseParenExpr(line string) *ParenExpr { @@ -19,11 +19,12 @@ func parseParenExpr(line string) *ParenExpr { Address: groups["address"], Position: groups["position"], Type: groups["type"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *ParenExpr) Render() []string { - a := renderExpression(n.Children[0]) - return []string{fmt.Sprintf("(%s)", a[0]), a[1]} +func (n *ParenExpr) render(ast *Ast) (string, string) { + a, aType := renderExpression(ast, n.Children[0]) + src := fmt.Sprintf("(%s)", a) + return src, aType } diff --git a/parm_var_decl.go b/ast/parm_var_decl.go similarity index 87% rename from parm_var_decl.go rename to ast/parm_var_decl.go index c30ddeee9..62b7e6f85 100644 --- a/parm_var_decl.go +++ b/ast/parm_var_decl.go @@ -1,4 +1,4 @@ -package main +package ast import "strings" @@ -10,7 +10,7 @@ type ParmVarDecl struct { Type string Type2 string IsUsed bool - Children []interface{} + Children []Node } func parseParmVarDecl(line string) *ParmVarDecl { @@ -42,6 +42,10 @@ func parseParmVarDecl(line string) *ParmVarDecl { Type: groups["type"], Type2: type2, IsUsed: len(groups["used"]) > 0, - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *ParmVarDecl) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/pointer_type.go b/ast/pointer_type.go similarity index 67% rename from pointer_type.go rename to ast/pointer_type.go index f3d766825..f0c1e08b9 100644 --- a/pointer_type.go +++ b/ast/pointer_type.go @@ -1,9 +1,9 @@ -package main +package ast type PointerType struct { Address string Type string - Children []interface{} + Children []Node } func parsePointerType(line string) *PointerType { @@ -15,6 +15,10 @@ func parsePointerType(line string) *PointerType { return &PointerType{ Address: groups["address"], Type: groups["type"], - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *PointerType) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/predefined_expr.go b/ast/predefined_expr.go similarity index 71% rename from predefined_expr.go rename to ast/predefined_expr.go index e993dbe4b..4e2752998 100644 --- a/predefined_expr.go +++ b/ast/predefined_expr.go @@ -1,4 +1,4 @@ -package main +package ast import "fmt" @@ -8,7 +8,7 @@ type PredefinedExpr struct { Type string Name string Lvalue bool - Children []interface{} + Children []Node } func parsePredefinedExpr(line string) *PredefinedExpr { @@ -23,19 +23,20 @@ func parsePredefinedExpr(line string) *PredefinedExpr { Type: groups["type"], Name: groups["name"], Lvalue: true, - Children: []interface{}{}, + Children: []Node{}, } } -func (n *PredefinedExpr) Render() []string { +func (n *PredefinedExpr) render(ast *Ast) (string, string) { if n.Name == "__PRETTY_FUNCTION__" { // FIXME - return []string{"\"void print_number(int *)\"", "const char*"} + return "\"void print_number(int *)\"", "const char*" } if n.Name == "__func__" { // FIXME - return []string{fmt.Sprintf("\"%s\"", "print_number"), "const char*"} + src := fmt.Sprintf("\"%s\"", "print_number") + return src, "const char*" } panic(fmt.Sprintf("renderExpression: unknown PredefinedExpr: %s", n.Name)) diff --git a/qual_type.go b/ast/qual_type.go similarity index 71% rename from qual_type.go rename to ast/qual_type.go index 83aa205ff..4825bc7b1 100644 --- a/qual_type.go +++ b/ast/qual_type.go @@ -1,10 +1,10 @@ -package main +package ast type QualType struct { Address string Type string Kind string - Children []interface{} + Children []Node } func parseQualType(line string) *QualType { @@ -17,6 +17,10 @@ func parseQualType(line string) *QualType { Address: groups["address"], Type: groups["type"], Kind: groups["kind"], - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *QualType) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/record.go b/ast/record.go similarity index 77% rename from record.go rename to ast/record.go index 32f520699..82d2a5682 100644 --- a/record.go +++ b/ast/record.go @@ -1,4 +1,4 @@ -package main +package ast type Record struct { Address string @@ -18,3 +18,7 @@ func parseRecord(line string) *Record { Children: []interface{}{}, } } + +func (n *Record) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/record_decl.go b/ast/record_decl.go similarity index 74% rename from record_decl.go rename to ast/record_decl.go index 54aaf74c8..cca71a502 100644 --- a/record_decl.go +++ b/ast/record_decl.go @@ -1,4 +1,4 @@ -package main +package ast import ( "bytes" @@ -14,7 +14,7 @@ type RecordDecl struct { Kind string Name string Definition bool - Children []interface{} + Children []Node } func parseRecordDecl(line string) *RecordDecl { @@ -46,28 +46,31 @@ func parseRecordDecl(line string) *RecordDecl { Kind: groups["kind"], Name: name, Definition: definition, - Children: []interface{}{}, + Children: []Node{}, } } -func (n *RecordDecl) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { +func (n *RecordDecl) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) name := strings.TrimSpace(n.Name) if name == "" || typeIsAlreadyDefined(name) { - return + return "", "" } typeIsNowDefined(name) if n.Kind == "union" { - return + return "", "" } - printLine(out, fmt.Sprintf("type %s %s {", name, n.Kind), indent) + printLine(out, fmt.Sprintf("type %s %s {", name, n.Kind), ast.indent) if len(n.Children) > 0 { for _, c := range n.Children { - Render(out, c, functionName, indent+1, "") + src, _ := renderExpression(ast, c) + printLine(out, src, ast.indent) } } - printLine(out, "}\n", indent) + printLine(out, "}\n", ast.indent) + return out.String(), "" } diff --git a/record_type.go b/ast/record_type.go similarity index 67% rename from record_type.go rename to ast/record_type.go index 958edc858..6c633808e 100644 --- a/record_type.go +++ b/ast/record_type.go @@ -1,9 +1,9 @@ -package main +package ast type RecordType struct { Address string Type string - Children []interface{} + Children []Node } func parseRecordType(line string) *RecordType { @@ -15,6 +15,10 @@ func parseRecordType(line string) *RecordType { return &RecordType{ Address: groups["address"], Type: groups["type"], - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *RecordType) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/resolve.go b/ast/resolve.go similarity index 91% rename from resolve.go rename to ast/resolve.go index d4ca87fab..0e6be1796 100644 --- a/resolve.go +++ b/ast/resolve.go @@ -1,4 +1,4 @@ -package main +package ast import ( "fmt" @@ -74,13 +74,18 @@ func typeIsNowDefined(typeName string) { TypesAlreadyDefined = append(TypesAlreadyDefined, typeName) } -func resolveType(s string) string { +func resolveType(ast *Ast, s string) string { + // Remove any whitespace or attributes that are not relevant to Go. s = strings.Replace(s, "const ", "", -1) s = strings.Replace(s, "*__restrict", "*", -1) s = strings.Replace(s, "*restrict", "*", -1) s = strings.Trim(s, " \t\n\r") + if s == "char *[]" { + return "interface{}" + } + if s == "fpos_t" { return "int" } @@ -89,14 +94,14 @@ func resolveType(s string) string { // equivalent. For example float, int, etc. for k, v := range simpleResolveTypes { if k == s { - return importType(v) + return ast.importType(v) } } // If the type is already defined we can proceed with the same name. for _, v := range TypesAlreadyDefined { if v == s { - return importType(s) + return ast.importType(s) } } @@ -107,7 +112,7 @@ func resolveType(s string) string { for _, v := range simpleResolveTypes { if v == s { - return "*" + importType(simpleResolveTypes[s]) + return "*" + ast.importType(simpleResolveTypes[s]) } } @@ -117,7 +122,7 @@ func resolveType(s string) string { for _, v := range simpleResolveTypes { if v == s { - return importType(simpleResolveTypes[s]) + return ast.importType(simpleResolveTypes[s]) } } @@ -142,7 +147,7 @@ func resolveType(s string) string { // It may be a pointer of a simple type. For example, float *, int *, // etc. if regexp.MustCompile("[\\w ]+\\*+$").MatchString(s) { - return "*" + resolveType(strings.TrimSpace(s[:len(s)-2])) + return "*" + resolveType(ast, strings.TrimSpace(s[:len(s)-2])) } // Function pointers are not yet supported. In th mean time they will be @@ -161,7 +166,7 @@ func resolveType(s string) string { // It could be an array of fixed length. search2 := regexp.MustCompile("([\\w ]+)\\[(\\d+)\\]").FindStringSubmatch(s) if len(search2) > 0 { - return fmt.Sprintf("[%s]%s", search2[2], resolveType(search2[1])) + return fmt.Sprintf("[%s]%s", search2[2], resolveType(ast, search2[1])) } panic(fmt.Sprintf("'%s'", s)) diff --git a/restrict_attr.go b/ast/restrict_attr.go similarity index 81% rename from restrict_attr.go rename to ast/restrict_attr.go index f827db1d5..3935a91d3 100644 --- a/restrict_attr.go +++ b/ast/restrict_attr.go @@ -1,4 +1,4 @@ -package main +package ast type RestrictAttr struct { Address string @@ -20,3 +20,7 @@ func parseRestrictAttr(line string) *RestrictAttr { Children: []interface{}{}, } } + +func (n *RestrictAttr) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/ast/return_stmt.go b/ast/return_stmt.go new file mode 100644 index 000000000..824f772f2 --- /dev/null +++ b/ast/return_stmt.go @@ -0,0 +1,38 @@ +package ast + +import ( + "bytes" +) + +type ReturnStmt struct { + Address string + Position string + Children []Node +} + +func parseReturnStmt(line string) *ReturnStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &ReturnStmt{ + Address: groups["address"], + Position: groups["position"], + Children: []Node{}, + } +} + +func (n *ReturnStmt) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) + r := "return" + + if len(n.Children) > 0 && ast.functionName != "main" { + re, reType := renderExpression(ast, n.Children[0]) + r = "return " + cast(ast, re, reType, "int") + } + + printLine(out, r, ast.indent) + + return out.String(), "" +} diff --git a/string_literal.go b/ast/string_literal.go similarity index 75% rename from string_literal.go rename to ast/string_literal.go index c831cec32..68f9e52be 100644 --- a/string_literal.go +++ b/ast/string_literal.go @@ -1,4 +1,4 @@ -package main +package ast import ( "fmt" @@ -30,9 +30,7 @@ func parseStringLiteral(line string) *StringLiteral { } } -func (n *StringLiteral) Render() []string { - return []string{ - fmt.Sprintf("\"%s\"", strings.Replace(n.Value, "\n", "\\n", -1)), - "const char *", - } +func (n *StringLiteral) render(ast *Ast) (string, string) { + src := fmt.Sprintf("\"%s\"", strings.Replace(n.Value, "\n", "\\n", -1)) + return src, "const char *" } diff --git a/ast/translation_unit_decl.go b/ast/translation_unit_decl.go new file mode 100644 index 000000000..2f54d01b7 --- /dev/null +++ b/ast/translation_unit_decl.go @@ -0,0 +1,29 @@ +package ast + +import ( + "bytes" +) + +type TranslationUnitDecl struct { + Address string + Children []Node +} + +func parseTranslationUnitDecl(line string) *TranslationUnitDecl { + groups := groupsFromRegex("", line) + + return &TranslationUnitDecl{ + Address: groups["address"], + Children: []Node{}, + } +} + +func (n *TranslationUnitDecl) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) + for _, c := range n.Children { + src, _ := renderExpression(ast, c) + printLine(out, src, ast.indent) + } + + return out.String(), "" +} diff --git a/typedef.go b/ast/typedef.go similarity index 77% rename from typedef.go rename to ast/typedef.go index 73e2471bc..c412c52dd 100644 --- a/typedef.go +++ b/ast/typedef.go @@ -1,4 +1,4 @@ -package main +package ast type Typedef struct { Address string @@ -18,3 +18,7 @@ func parseTypedef(line string) *Typedef { Children: []interface{}{}, } } + +func (n *Typedef) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/typedef_decl.go b/ast/typedef_decl.go similarity index 76% rename from typedef_decl.go rename to ast/typedef_decl.go index c1ffd9a46..fceba9317 100644 --- a/typedef_decl.go +++ b/ast/typedef_decl.go @@ -1,4 +1,4 @@ -package main +package ast import ( "bytes" @@ -15,7 +15,7 @@ type TypedefDecl struct { Type2 string IsImplicit bool IsReferenced bool - Children []interface{} + Children []Node } func parseTypedefDecl(line string) *TypedefDecl { @@ -44,14 +44,16 @@ func parseTypedefDecl(line string) *TypedefDecl { Type2: type2, IsImplicit: len(groups["implicit"]) > 0, IsReferenced: len(groups["referenced"]) > 0, - Children: []interface{}{}, + Children: []Node{}, } } -func (n *TypedefDecl) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { +func (n *TypedefDecl) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) name := strings.TrimSpace(n.Name) + if typeIsAlreadyDefined(name) { - return + return "", "" } typeIsNowDefined(name) @@ -62,23 +64,25 @@ func (n *TypedefDecl) RenderLine(out *bytes.Buffer, functionName string, indent // return n.Type = strings.Replace(n.Type, "unsigned", "", -1) - resolved_type := resolveType(n.Type) + resolvedType := resolveType(ast, n.Type) if name == "__mbstate_t" { - addImport("github.com/elliotchance/c2go/darwin") - resolved_type = "darwin.C__mbstate_t" + ast.addImport("github.com/elliotchance/c2go/darwin") + resolvedType = "darwin.C__mbstate_t" } if name == "__darwin_ct_rune_t" { - addImport("github.com/elliotchance/c2go/darwin") - resolved_type = "darwin.C__darwin_ct_rune_t" + ast.addImport("github.com/elliotchance/c2go/darwin") + resolvedType = "darwin.C__darwin_ct_rune_t" } if name == "__builtin_va_list" || name == "__qaddr_t" || name == "definition" || name == "_IO_lock_t" || name == "va_list" || name == "fpos_t" || name == "__NSConstantString" || name == "__darwin_va_list" || name == "__fsid_t" || name == "_G_fpos_t" || name == "_G_fpos64_t" { - return + return "", "" } - printLine(out, fmt.Sprintf("type %s %s\n", name, resolved_type), indent) + printLine(out, fmt.Sprintf("type %s %s\n", name, resolvedType), ast.indent) + + return out.String(), "" } diff --git a/typedef_type.go b/ast/typedef_type.go similarity index 71% rename from typedef_type.go rename to ast/typedef_type.go index b061adec5..e97a4182f 100644 --- a/typedef_type.go +++ b/ast/typedef_type.go @@ -1,10 +1,10 @@ -package main +package ast type TypedefType struct { Address string Type string Tags string - Children []interface{} + Children []Node } func parseTypedefType(line string) *TypedefType { @@ -17,6 +17,10 @@ func parseTypedefType(line string) *TypedefType { Address: groups["address"], Type: groups["type"], Tags: groups["tags"], - Children: []interface{}{}, + Children: []Node{}, } } + +func (n *TypedefType) render(ast *Ast) (string, string) { + return "", "" +} diff --git a/unary_operator.go b/ast/unary_operator.go similarity index 53% rename from unary_operator.go rename to ast/unary_operator.go index e86b6ac29..3f6cb3078 100644 --- a/unary_operator.go +++ b/ast/unary_operator.go @@ -1,4 +1,4 @@ -package main +package ast import "fmt" @@ -9,7 +9,7 @@ type UnaryOperator struct { IsLvalue bool IsPrefix bool Operator string - Children []interface{} + Children []Node } func parseUnaryOperator(line string) *UnaryOperator { @@ -30,38 +30,38 @@ func parseUnaryOperator(line string) *UnaryOperator { IsLvalue: len(groups["lvalue"]) > 0, IsPrefix: len(groups["prefix"]) > 0, Operator: groups["operator"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *UnaryOperator) Render() []string { +func (n *UnaryOperator) render(ast *Ast) (string, string) { operator := n.Operator - expr := renderExpression(n.Children[0]) + expr, exprType := renderExpression(ast, n.Children[0]) if operator == "!" { - if expr[1] == "bool" { - return []string{fmt.Sprintf("!(%s)", expr[0]), expr[1]} + if exprType == "bool" { + return fmt.Sprintf("!(%s)", expr), exprType } - addImport("github.com/elliotchance/c2go/noarch") - return []string{fmt.Sprintf("%s(%s)", fmt.Sprintf("noarch.Not%s", ucfirst(expr[1])), expr[0]), expr[1]} + ast.addImport("github.com/elliotchance/c2go/noarch") + return fmt.Sprintf("%s(%s)", fmt.Sprintf("noarch.Not%s", ucfirst(exprType)), expr), exprType } if operator == "*" { - if expr[1] == "const char *" { - return []string{fmt.Sprintf("%s[0]", expr[0]), "char"} + if exprType == "const char *" { + return fmt.Sprintf("%s[0]", expr), "char" } - return []string{fmt.Sprintf("*%s", expr[0]), "int"} + return fmt.Sprintf("*%s", expr), "int" } if operator == "++" { - return []string{fmt.Sprintf("%s += 1", expr[0]), expr[1]} + return fmt.Sprintf("%s += 1", expr), exprType } if operator == "~" { operator = "^" } - return []string{fmt.Sprintf("%s%s", operator, expr[0]), expr[1]} + return fmt.Sprintf("%s%s", operator, expr), exprType } diff --git a/util.go b/ast/util.go similarity index 98% rename from util.go rename to ast/util.go index d7148f543..1af1e304b 100644 --- a/util.go +++ b/ast/util.go @@ -1,4 +1,4 @@ -package main +package ast import ( "strconv" diff --git a/var_decl.go b/ast/var_decl.go similarity index 67% rename from var_decl.go rename to ast/var_decl.go index 92bfabec2..3cbc35b90 100644 --- a/var_decl.go +++ b/ast/var_decl.go @@ -1,7 +1,6 @@ -package main +package ast import ( - "bytes" "fmt" "strings" ) @@ -16,7 +15,7 @@ type VarDecl struct { IsExtern bool IsUsed bool IsCInit bool - Children []interface{} + Children []Node } func parseVarDecl(line string) *VarDecl { @@ -46,14 +45,25 @@ func parseVarDecl(line string) *VarDecl { IsExtern: len(groups["extern"]) > 0, IsUsed: len(groups["used"]) > 0, IsCInit: len(groups["cinit"]) > 0, - Children: []interface{}{}, + Children: []Node{}, } } -func (n *VarDecl) Render() []string { - theType := resolveType(n.Type) +func (n *VarDecl) render(ast *Ast) (string, string) { + theType := resolveType(ast, n.Type) name := n.Name + // FIXME: These names dont seem to work when testing more than 1 file + if name == "_LIB_VERSION" || + name == "_IO_2_1_stdin_" || + name == "_IO_2_1_stdout_" || + name == "_IO_2_1_stderr_" || + name == "stdin" || + name == "stdout" || + name == "stderr" { + return "", "" + } + // Go does not allow the name of a variable to be called "type". // For the moment I will rename this to avoid the error. if name == "type" { @@ -63,15 +73,13 @@ func (n *VarDecl) Render() []string { suffix := "" if len(n.Children) > 0 { children := n.Children - suffix = fmt.Sprintf(" = %s", renderExpression(children[0])[0]) + src, _ := renderExpression(ast, children[0]) + suffix = fmt.Sprintf(" = %s", src) } if suffix == " = (0)" { suffix = " = nil" } - return []string{fmt.Sprintf("var %s %s%s", name, theType, suffix), "unknown3"} -} - -func (n *VarDecl) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { + return fmt.Sprintf("var %s %s%s", name, theType, suffix), "unknown3" } diff --git a/while_stmt.go b/ast/while_stmt.go similarity index 51% rename from while_stmt.go rename to ast/while_stmt.go index 86e5a676b..a9728252f 100644 --- a/while_stmt.go +++ b/ast/while_stmt.go @@ -1,4 +1,4 @@ -package main +package ast import ( "bytes" @@ -8,7 +8,7 @@ import ( type WhileStmt struct { Address string Position string - Children []interface{} + Children []Node } func parseWhileStmt(line string) *WhileStmt { @@ -20,20 +20,23 @@ func parseWhileStmt(line string) *WhileStmt { return &WhileStmt{ Address: groups["address"], Position: groups["position"], - Children: []interface{}{}, + Children: []Node{}, } } -func (n *WhileStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { +func (n *WhileStmt) render(ast *Ast) (string, string) { + out := bytes.NewBuffer([]byte{}) // TODO: The first child of a WhileStmt appears to always be null. // Are there any cases where it is used? children := n.Children[1:] - e := renderExpression(children[0]) - printLine(out, fmt.Sprintf("for %s {", cast(e[0], e[1], "bool")), indent) + e, eType := renderExpression(ast, children[0]) + printLine(out, fmt.Sprintf("for %s {", cast(ast, e, eType, "bool")), ast.indent) - // FIXME: Does this do anything? - Render(out, children[1], functionName, indent+1, returnType) + body, _ := renderExpression(ast, children[1]) + printLine(out, body, ast.indent+1) - printLine(out, "}", indent) + printLine(out, "}", ast.indent) + + return out.String(), "" } diff --git a/conditional_operator.go b/conditional_operator.go deleted file mode 100644 index a552a3c83..000000000 --- a/conditional_operator.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import "fmt" - -type ConditionalOperator struct { - Address string - Position string - Type string - Children []interface{} -} - -func parseConditionalOperator(line string) *ConditionalOperator { - groups := groupsFromRegex( - `<(?P.*)> '(?P.*?)'`, - line, - ) - - return &ConditionalOperator{ - Address: groups["address"], - Position: groups["position"], - Type: groups["type"], - Children: []interface{}{}, - } -} - -func (n *ConditionalOperator) Render() []string { - a := renderExpression(n.Children[0])[0] - b := renderExpression(n.Children[1])[0] - c := renderExpression(n.Children[2])[0] - - addImport("github.com/elliotchance/c2go/noarch") - return []string{ - fmt.Sprintf("noarch.Ternary(%s, func () interface{} { return %s }, func () interface{} { return %s })", a, b, c), - n.Type, - } -} diff --git a/import.go b/import.go deleted file mode 100644 index 86c3121e8..000000000 --- a/import.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import "strings" - -var Imports []string - -func init() { - initImports() -} - -func addImport(importName string) { - for _, i := range Imports { - if i == importName { - return - } - } - - Imports = append(Imports, importName) -} - -func importType(typeName string) string { - if strings.Index(typeName, ".") != -1 { - parts := strings.Split(typeName, ".") - addImport(strings.Join(parts[:len(parts)-1], ".")) - - parts2 := strings.Split(typeName, "/") - return parts2[len(parts2)-1] - } - - return typeName -} - -func initImports() { - Imports = []string{"fmt"} -} diff --git a/main.go b/main.go index e0c663081..f8daf398b 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "flag" "fmt" "io/ioutil" @@ -10,6 +9,10 @@ import ( "reflect" "regexp" "strings" + + "go/format" + + "github.com/bongo227/c2go/ast" ) var ( @@ -39,7 +42,7 @@ func convertLinesToNodes(lines []string) []interface{} { } offset := len(indentAndType[1]) - node := Parse(line[offset:]) + node := ast.Parse(line[offset:]) indentLevel := len(indentAndType[1]) / 2 nodes = append(nodes, []interface{}{indentLevel, node}) @@ -49,9 +52,9 @@ func convertLinesToNodes(lines []string) []interface{} { } // buildTree convert an array of nodes, each prefixed with a depth into a tree. -func buildTree(nodes []interface{}, depth int) []interface{} { +func buildTree(nodes []interface{}, depth int) []ast.Node { if len(nodes) == 0 { - return []interface{}{} + return []ast.Node{} } // Split the list into sections, treat each section as a a tree with its own root. @@ -64,7 +67,7 @@ func buildTree(nodes []interface{}, depth int) []interface{} { } } - results := []interface{}{} + results := []ast.Node{} for _, section := range sections { slice := []interface{}{} for _, n := range section { @@ -74,15 +77,17 @@ func buildTree(nodes []interface{}, depth int) []interface{} { } children := buildTree(slice, depth+1) - result := section[0].([]interface{})[1] + if result, ok := section[0].([]interface{})[1].(ast.Node); ok { + if len(children) > 0 { + c := reflect.ValueOf(result).Elem().FieldByName("Children") + slice := reflect.AppendSlice(c, reflect.ValueOf(children)) + c.Set(slice) + } - if len(children) > 0 { - c := reflect.ValueOf(result).Elem().FieldByName("Children") - slice := reflect.AppendSlice(c, reflect.ValueOf(children)) - c.Set(slice) + results = append(results, result) + } else { + results = append(results, nil) } - - results = append(results, result) } return results @@ -161,21 +166,25 @@ func Start(args []string) string { // 3. Parse C and output Go //parts := strings.Split(cFilePath, "/") //go_file_path := fmt.Sprintf("%s.go", parts[len(parts) - 1][:len(parts) - 2]) - go_out := bytes.NewBuffer([]byte{}) - Render(go_out, tree[0], "", 0, "") + // Render(go_out, tree[0], "", 0, "") + astTree := ast.NewAst() + goOut := ast.Render(astTree, tree[0].(ast.Node)) + + // Format the code + goOutFmt, err := format.Source([]byte(goOut)) + if err != nil { + panic(err) + } // Put together the whole file all := "package main\n\nimport (\n" - for _, importName := range Imports { + for _, importName := range astTree.Imports() { all += fmt.Sprintf("\t\"%s\"\n", importName) } - all += ")\n\n" + go_out.String() - - // Reset the imports - initImports() + all += ")\n\n" + string(goOutFmt) return all } diff --git a/main_test.go b/main_test.go index 986b7c173..35f8e83aa 100644 --- a/main_test.go +++ b/main_test.go @@ -54,10 +54,11 @@ func TestIntegrationScripts(t *testing.T) { // Compile Go goSrc := Start([]string{file}) + // fmt.Println(goSrc) ioutil.WriteFile("build/main.go", []byte(goSrc), os.ModePerm) - err = exec.Command("go", "build", "-o", goPath, "build/main.go").Run() + buildErr, err := exec.Command("go", "build", "-o", goPath, "build/main.go").CombinedOutput() if err != nil { - t.Fatal(err) + t.Fatal(string(buildErr), err) } // Run Go program diff --git a/return_stmt.go b/return_stmt.go deleted file mode 100644 index e193b5c73..000000000 --- a/return_stmt.go +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import "bytes" - -type ReturnStmt struct { - Address string - Position string - Children []interface{} -} - -func parseReturnStmt(line string) *ReturnStmt { - groups := groupsFromRegex( - "<(?P.*)>", - line, - ) - - return &ReturnStmt{ - Address: groups["address"], - Position: groups["position"], - Children: []interface{}{}, - } -} - -func (n *ReturnStmt) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { - r := "return" - - if len(n.Children) > 0 && functionName != "main" { - re := renderExpression(n.Children[0]) - r = "return " + cast(re[0], re[1], "int") - } - - printLine(out, r, indent) -} diff --git a/translation_unit_decl.go b/translation_unit_decl.go deleted file mode 100644 index 4b860b123..000000000 --- a/translation_unit_decl.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import "bytes" - -type TranslationUnitDecl struct { - Address string - Children []interface{} -} - -func parseTranslationUnitDecl(line string) *TranslationUnitDecl { - groups := groupsFromRegex("", line) - - return &TranslationUnitDecl{ - Address: groups["address"], - Children: []interface{}{}, - } -} - -func (n *TranslationUnitDecl) RenderLine(out *bytes.Buffer, functionName string, indent int, returnType string) { - for _, c := range n.Children { - Render(out, c, functionName, indent, returnType) - } -}