From 6a9c5c281144420eebbeb8cb6c26acf10e367155 Mon Sep 17 00:00:00 2001 From: Greg Date: Tue, 9 Apr 2019 11:52:21 -0400 Subject: [PATCH] Initial commit. --- .gitignore | 3 + ast/aligned_attr.go | 47 +++ ast/aligned_attr_test.go | 24 ++ ast/alloc_size_attr.go | 57 +++ ast/alloc_size_attr_test.go | 27 ++ ast/always_inline_attr.go | 45 +++ ast/always_inline_attr_test.go | 17 + ast/array_filler.go | 36 ++ ast/array_filler_test.go | 20 ++ ast/array_subscript_expr.go | 54 +++ ast/array_subscript_expr_test.go | 36 ++ ast/asm_label_attr.go | 50 +++ ast/asm_label_attr_test.go | 26 ++ ast/ast.go | 323 +++++++++++++++++ ast/ast_test.go | 70 ++++ ast/attributed_type.go | 47 +++ ast/availability_attr.go | 69 ++++ ast/availability_attr_test.go | 116 ++++++ ast/binary_operator.go | 50 +++ ast/binary_operator_test.go | 27 ++ ast/block_command_comment.go | 46 +++ ast/block_command_comment_test.go | 18 + ast/block_pointer_type.go | 44 +++ ast/break_stmt.go | 44 +++ ast/break_stmt_test.go | 17 + ast/builtin_type.go | 44 +++ ast/builtin_type_test.go | 22 ++ ast/c_style_cast_expr.go | 56 +++ ast/c_style_cast_expr_test.go | 27 ++ ast/call_expr.go | 46 +++ ast/call_expr_test.go | 24 ++ ast/case_stmt.go | 41 +++ ast/case_stmt_test.go | 17 + ast/character_literal.go | 52 +++ ast/character_literal_test.go | 19 + ast/compound_assign_operator.go | 56 +++ ast/compound_assign_operator_test.go | 21 ++ ast/compound_literal_expr.go | 48 +++ ast/compound_literal_expr_test.go | 19 + ast/compound_stmt.go | 48 +++ ast/compound_stmt_test.go | 22 ++ ast/conditional_operator.go | 46 +++ ast/conditional_operator_test.go | 18 + ast/const_attr.go | 47 +++ ast/const_attr_test.go | 18 + ast/constant_array_type.go | 50 +++ ast/constant_array_type_test.go | 24 ++ ast/continue_stmt.go | 44 +++ ast/continue_stmt_test.go | 17 + ast/decayed_type.go | 44 +++ ast/decayed_type_test.go | 17 + ast/decl_ref_expr.go | 71 ++++ ast/decl_ref_expr_test.go | 77 ++++ ast/decl_stmt.go | 44 +++ ast/decl_stmt_test.go | 17 + ast/default_stmt.go | 41 +++ ast/default_stmt_test.go | 17 + ast/deprecated_attr.go | 51 +++ ast/deprecated_attr_test.go | 36 ++ ast/disable_tail_calls_attr.go | 45 +++ ast/disable_tail_calls_attr_test.go | 17 + ast/do_stmt.go | 44 +++ ast/do_stmt_test.go | 17 + ast/elaborated_type.go | 46 +++ ast/elaborated_type_test.go | 18 + ast/empty_decl.go | 47 +++ ast/empty_decl_test.go | 18 + ast/enum.go | 44 +++ ast/enum_constant_decl.go | 56 +++ ast/enum_constant_decl_test.go | 30 ++ ast/enum_decl.go | 52 +++ ast/enum_decl_test.go | 26 ++ ast/enum_test.go | 17 + ast/enum_type.go | 44 +++ ast/enum_type_test.go | 17 + ast/field.go | 46 +++ ast/field_decl.go | 67 ++++ ast/field_decl_test.go | 122 +++++++ ast/field_test.go | 18 + ast/floating_literal.go | 114 ++++++ ast/floating_literal_test.go | 26 ++ ast/for_stmt.go | 44 +++ ast/for_stmt_test.go | 17 + ast/format_arg_attr.go | 48 +++ ast/format_arg_attr_test.go | 18 + ast/format_attr.go | 64 ++++ ast/format_attr_test.go | 42 +++ ast/full_comment.go | 44 +++ ast/full_comment_test.go | 17 + ast/function_decl.go | 85 +++++ ast/function_decl_test.go | 222 ++++++++++++ ast/function_proto_type.go | 46 +++ ast/function_proto_type_test.go | 18 + ast/gcc_asm_stmt.go | 44 +++ ast/gcc_asm_stmt_test.go | 17 + ast/go_stmt.go | 48 +++ ast/go_stmt_test.go | 19 + ast/html_end_tag_comment.go | 46 +++ ast/html_end_tag_comment_test.go | 18 + ast/html_start_tag_comment.go | 46 +++ ast/html_start_tag_comment_test.go | 18 + ast/if_stmt.go | 44 +++ ast/if_stmt_test.go | 17 + ast/implicit_cast_expr.go | 56 +++ ast/implicit_cast_expr_test.go | 42 +++ ast/implicit_value_init_expr.go | 48 +++ ast/implicit_value_init_expr_test.go | 26 ++ ast/incomplete_array_type.go | 44 +++ ast/incomplete_array_type_test.go | 17 + ast/indirect_field_decl.go | 58 +++ ast/indirect_field_decl_test.go | 21 ++ ast/init_list_expr.go | 48 +++ ast/init_list_expr_test.go | 31 ++ ast/inline_command_comment.go | 46 +++ ast/inline_command_comment_test.go | 18 + ast/integer_literal.go | 48 +++ ast/integer_literal_test.go | 19 + ast/label_stmt.go | 46 +++ ast/label_stmt_test.go | 18 + ast/malloc_attr.go | 45 +++ ast/malloc_attr_test.go | 17 + ast/max_field_alignment_attr.go | 49 +++ ast/max_field_alignment_attr_test.go | 24 ++ ast/member_expr.go | 93 +++++ ast/member_expr_test.go | 96 +++++ ast/mode_attr.go | 47 +++ ast/mode_attr_test.go | 18 + ast/no_inline_attr.go | 45 +++ ast/no_inline_attr_test.go | 17 + ast/no_throw_attr.go | 52 +++ ast/no_throw_attr_test.go | 40 +++ ast/non_null_attr.go | 83 +++++ ast/non_null_attr_test.go | 82 +++++ ast/not_tail_called_attr.go | 45 +++ ast/not_tail_called_attr_test.go | 17 + ast/objc_interface.go | 44 +++ ast/objc_interface_decl.go | 66 ++++ ast/objc_interface_type.go | 44 +++ ast/objc_method.go | 44 +++ ast/objc_method_decl.go | 70 ++++ ast/objc_object_pointer_type.go | 44 +++ ast/objc_object_type.go | 44 +++ ast/objc_protocol.go | 44 +++ ast/offset_of_expr.go | 46 +++ ast/offset_of_expr_test.go | 18 + ast/packed_attr.go | 45 +++ ast/packed_attr_test.go | 17 + ast/paragraph_comment.go | 44 +++ ast/paragraph_comment_test.go | 17 + ast/param_command_comment.go | 46 +++ ast/param_command_comment_test.go | 18 + ast/paren_expr.go | 55 +++ ast/paren_expr_test.go | 39 ++ ast/paren_type.go | 43 +++ ast/paren_type_test.go | 18 + ast/parm_var_decl.go | 80 +++++ ast/parm_var_decl_test.go | 119 +++++++ ast/pointer_type.go | 44 +++ ast/pointer_type_test.go | 17 + ast/position.go | 416 ++++++++++++++++++++++ ast/position_test.go | 109 ++++++ ast/predefined_expr.go | 50 +++ ast/predefined_expr_test.go | 20 ++ ast/pure_attr.go | 51 +++ ast/pure_attr_test.go | 26 ++ ast/qual_type.go | 46 +++ ast/qual_type_test.go | 18 + ast/record.go | 44 +++ ast/record_decl.go | 74 ++++ ast/record_decl_test.go | 62 ++++ ast/record_test.go | 17 + ast/record_type.go | 44 +++ ast/record_type_test.go | 17 + ast/restrict_attr.go | 47 +++ ast/restrict_attr_test.go | 18 + ast/return_stmt.go | 44 +++ ast/return_stmt_test.go | 17 + ast/returns_twice_attr.go | 52 +++ ast/returns_twice_attr_test.go | 26 ++ ast/sentinel_attr.go | 60 ++++ ast/sentinel_attr_test.go | 19 + ast/stmt_expr.go | 46 +++ ast/stmt_expr_test.go | 18 + ast/string_literal.go | 60 ++++ ast/string_literal_test.go | 28 ++ ast/switch_stmt.go | 41 +++ ast/switch_stmt_test.go | 17 + ast/text_comment.go | 46 +++ ast/text_comment_test.go | 18 + ast/translation_unit_decl.go | 39 ++ ast/translation_unit_decl_test.go | 16 + ast/transparent_union_attr.go | 42 +++ ast/transparent_union_attr_test.go | 17 + ast/traverse.go | 28 ++ ast/typedef.go | 44 +++ ast/typedef_decl.go | 72 ++++ ast/typedef_decl_test.go | 100 ++++++ ast/typedef_test.go | 17 + ast/typedef_type.go | 46 +++ ast/typedef_type_test.go | 18 + ast/unary_expr_or_type_trait_expr.go | 57 +++ ast/unary_expr_or_type_trait_expr_test.go | 48 +++ ast/unary_operator.go | 59 +++ ast/unary_operator_test.go | 52 +++ ast/unknown.go | 60 ++++ ast/unused_attr.go | 47 +++ ast/unused_attr_test.go | 24 ++ ast/util.go | 82 +++++ ast/va_arg_expr.go | 46 +++ ast/va_arg_expr_test.go | 18 + ast/var_decl.go | 87 +++++ ast/var_decl_test.go | 172 +++++++++ ast/vector_type.go | 51 +++ ast/verbatim_block_comment.go | 50 +++ ast/verbatim_block_comment_test.go | 19 + ast/verbatim_block_line_comment.go | 46 +++ ast/verbatim_block_line_comment_test.go | 18 + ast/verbatim_line_comment.go | 46 +++ ast/verbatim_line_comment_test.go | 18 + ast/visibility_attr.go | 51 +++ ast/visibility_attr_test.go | 26 ++ ast/warn_unused_result_attr.go | 42 +++ ast/warn_unused_result_attr_test.go | 22 ++ ast/weak_attr.go | 43 +++ ast/weak_attr_test.go | 17 + ast/while_stmt.go | 44 +++ ast/while_stmt_test.go | 17 + main.go | 331 +++++++++++++++++ objc/main.m | 8 + wrap/main.go | 29 ++ 230 files changed, 10509 insertions(+) create mode 100644 .gitignore create mode 100644 ast/aligned_attr.go create mode 100644 ast/aligned_attr_test.go create mode 100644 ast/alloc_size_attr.go create mode 100644 ast/alloc_size_attr_test.go create mode 100644 ast/always_inline_attr.go create mode 100644 ast/always_inline_attr_test.go create mode 100644 ast/array_filler.go create mode 100644 ast/array_filler_test.go create mode 100644 ast/array_subscript_expr.go create mode 100644 ast/array_subscript_expr_test.go create mode 100644 ast/asm_label_attr.go create mode 100644 ast/asm_label_attr_test.go create mode 100644 ast/ast.go create mode 100644 ast/ast_test.go create mode 100644 ast/attributed_type.go create mode 100644 ast/availability_attr.go create mode 100644 ast/availability_attr_test.go create mode 100644 ast/binary_operator.go create mode 100644 ast/binary_operator_test.go create mode 100644 ast/block_command_comment.go create mode 100644 ast/block_command_comment_test.go create mode 100644 ast/block_pointer_type.go create mode 100644 ast/break_stmt.go create mode 100644 ast/break_stmt_test.go create mode 100644 ast/builtin_type.go create mode 100644 ast/builtin_type_test.go create mode 100644 ast/c_style_cast_expr.go create mode 100644 ast/c_style_cast_expr_test.go create mode 100644 ast/call_expr.go create mode 100644 ast/call_expr_test.go create mode 100644 ast/case_stmt.go create mode 100644 ast/case_stmt_test.go create mode 100644 ast/character_literal.go create mode 100644 ast/character_literal_test.go create mode 100644 ast/compound_assign_operator.go create mode 100644 ast/compound_assign_operator_test.go create mode 100644 ast/compound_literal_expr.go create mode 100644 ast/compound_literal_expr_test.go create mode 100644 ast/compound_stmt.go create mode 100644 ast/compound_stmt_test.go create mode 100644 ast/conditional_operator.go create mode 100644 ast/conditional_operator_test.go create mode 100644 ast/const_attr.go create mode 100644 ast/const_attr_test.go create mode 100644 ast/constant_array_type.go create mode 100644 ast/constant_array_type_test.go create mode 100644 ast/continue_stmt.go create mode 100644 ast/continue_stmt_test.go create mode 100644 ast/decayed_type.go create mode 100644 ast/decayed_type_test.go create mode 100644 ast/decl_ref_expr.go create mode 100644 ast/decl_ref_expr_test.go create mode 100644 ast/decl_stmt.go create mode 100644 ast/decl_stmt_test.go create mode 100644 ast/default_stmt.go create mode 100644 ast/default_stmt_test.go create mode 100644 ast/deprecated_attr.go create mode 100644 ast/deprecated_attr_test.go create mode 100644 ast/disable_tail_calls_attr.go create mode 100644 ast/disable_tail_calls_attr_test.go create mode 100644 ast/do_stmt.go create mode 100644 ast/do_stmt_test.go create mode 100644 ast/elaborated_type.go create mode 100644 ast/elaborated_type_test.go create mode 100644 ast/empty_decl.go create mode 100644 ast/empty_decl_test.go create mode 100644 ast/enum.go create mode 100644 ast/enum_constant_decl.go create mode 100644 ast/enum_constant_decl_test.go create mode 100644 ast/enum_decl.go create mode 100644 ast/enum_decl_test.go create mode 100644 ast/enum_test.go create mode 100644 ast/enum_type.go create mode 100644 ast/enum_type_test.go create mode 100644 ast/field.go create mode 100644 ast/field_decl.go create mode 100644 ast/field_decl_test.go create mode 100644 ast/field_test.go create mode 100644 ast/floating_literal.go create mode 100644 ast/floating_literal_test.go create mode 100644 ast/for_stmt.go create mode 100644 ast/for_stmt_test.go create mode 100644 ast/format_arg_attr.go create mode 100644 ast/format_arg_attr_test.go create mode 100644 ast/format_attr.go create mode 100644 ast/format_attr_test.go create mode 100644 ast/full_comment.go create mode 100644 ast/full_comment_test.go create mode 100644 ast/function_decl.go create mode 100644 ast/function_decl_test.go create mode 100644 ast/function_proto_type.go create mode 100644 ast/function_proto_type_test.go create mode 100644 ast/gcc_asm_stmt.go create mode 100644 ast/gcc_asm_stmt_test.go create mode 100644 ast/go_stmt.go create mode 100644 ast/go_stmt_test.go create mode 100644 ast/html_end_tag_comment.go create mode 100644 ast/html_end_tag_comment_test.go create mode 100644 ast/html_start_tag_comment.go create mode 100644 ast/html_start_tag_comment_test.go create mode 100644 ast/if_stmt.go create mode 100644 ast/if_stmt_test.go create mode 100644 ast/implicit_cast_expr.go create mode 100644 ast/implicit_cast_expr_test.go create mode 100644 ast/implicit_value_init_expr.go create mode 100644 ast/implicit_value_init_expr_test.go create mode 100644 ast/incomplete_array_type.go create mode 100644 ast/incomplete_array_type_test.go create mode 100644 ast/indirect_field_decl.go create mode 100644 ast/indirect_field_decl_test.go create mode 100644 ast/init_list_expr.go create mode 100644 ast/init_list_expr_test.go create mode 100644 ast/inline_command_comment.go create mode 100644 ast/inline_command_comment_test.go create mode 100644 ast/integer_literal.go create mode 100644 ast/integer_literal_test.go create mode 100644 ast/label_stmt.go create mode 100644 ast/label_stmt_test.go create mode 100644 ast/malloc_attr.go create mode 100644 ast/malloc_attr_test.go create mode 100644 ast/max_field_alignment_attr.go create mode 100644 ast/max_field_alignment_attr_test.go create mode 100644 ast/member_expr.go create mode 100644 ast/member_expr_test.go create mode 100644 ast/mode_attr.go create mode 100644 ast/mode_attr_test.go create mode 100644 ast/no_inline_attr.go create mode 100644 ast/no_inline_attr_test.go create mode 100644 ast/no_throw_attr.go create mode 100644 ast/no_throw_attr_test.go create mode 100644 ast/non_null_attr.go create mode 100644 ast/non_null_attr_test.go create mode 100644 ast/not_tail_called_attr.go create mode 100644 ast/not_tail_called_attr_test.go create mode 100644 ast/objc_interface.go create mode 100644 ast/objc_interface_decl.go create mode 100644 ast/objc_interface_type.go create mode 100644 ast/objc_method.go create mode 100644 ast/objc_method_decl.go create mode 100644 ast/objc_object_pointer_type.go create mode 100644 ast/objc_object_type.go create mode 100644 ast/objc_protocol.go create mode 100644 ast/offset_of_expr.go create mode 100644 ast/offset_of_expr_test.go create mode 100644 ast/packed_attr.go create mode 100644 ast/packed_attr_test.go create mode 100644 ast/paragraph_comment.go create mode 100644 ast/paragraph_comment_test.go create mode 100644 ast/param_command_comment.go create mode 100644 ast/param_command_comment_test.go create mode 100644 ast/paren_expr.go create mode 100644 ast/paren_expr_test.go create mode 100644 ast/paren_type.go create mode 100644 ast/paren_type_test.go create mode 100644 ast/parm_var_decl.go create mode 100644 ast/parm_var_decl_test.go create mode 100644 ast/pointer_type.go create mode 100644 ast/pointer_type_test.go create mode 100644 ast/position.go create mode 100644 ast/position_test.go create mode 100644 ast/predefined_expr.go create mode 100644 ast/predefined_expr_test.go create mode 100644 ast/pure_attr.go create mode 100644 ast/pure_attr_test.go create mode 100644 ast/qual_type.go create mode 100644 ast/qual_type_test.go create mode 100644 ast/record.go create mode 100644 ast/record_decl.go create mode 100644 ast/record_decl_test.go create mode 100644 ast/record_test.go create mode 100644 ast/record_type.go create mode 100644 ast/record_type_test.go create mode 100644 ast/restrict_attr.go create mode 100644 ast/restrict_attr_test.go create mode 100644 ast/return_stmt.go create mode 100644 ast/return_stmt_test.go create mode 100644 ast/returns_twice_attr.go create mode 100644 ast/returns_twice_attr_test.go create mode 100644 ast/sentinel_attr.go create mode 100644 ast/sentinel_attr_test.go create mode 100644 ast/stmt_expr.go create mode 100644 ast/stmt_expr_test.go create mode 100644 ast/string_literal.go create mode 100644 ast/string_literal_test.go create mode 100644 ast/switch_stmt.go create mode 100644 ast/switch_stmt_test.go create mode 100644 ast/text_comment.go create mode 100644 ast/text_comment_test.go create mode 100644 ast/translation_unit_decl.go create mode 100644 ast/translation_unit_decl_test.go create mode 100644 ast/transparent_union_attr.go create mode 100644 ast/transparent_union_attr_test.go create mode 100644 ast/traverse.go create mode 100644 ast/typedef.go create mode 100644 ast/typedef_decl.go create mode 100644 ast/typedef_decl_test.go create mode 100644 ast/typedef_test.go create mode 100644 ast/typedef_type.go create mode 100644 ast/typedef_type_test.go create mode 100644 ast/unary_expr_or_type_trait_expr.go create mode 100644 ast/unary_expr_or_type_trait_expr_test.go create mode 100644 ast/unary_operator.go create mode 100644 ast/unary_operator_test.go create mode 100644 ast/unknown.go create mode 100644 ast/unused_attr.go create mode 100644 ast/unused_attr_test.go create mode 100644 ast/util.go create mode 100644 ast/va_arg_expr.go create mode 100644 ast/va_arg_expr_test.go create mode 100644 ast/var_decl.go create mode 100644 ast/var_decl_test.go create mode 100644 ast/vector_type.go create mode 100644 ast/verbatim_block_comment.go create mode 100644 ast/verbatim_block_comment_test.go create mode 100644 ast/verbatim_block_line_comment.go create mode 100644 ast/verbatim_block_line_comment_test.go create mode 100644 ast/verbatim_line_comment.go create mode 100644 ast/verbatim_line_comment_test.go create mode 100644 ast/visibility_attr.go create mode 100644 ast/visibility_attr_test.go create mode 100644 ast/warn_unused_result_attr.go create mode 100644 ast/warn_unused_result_attr_test.go create mode 100644 ast/weak_attr.go create mode 100644 ast/weak_attr_test.go create mode 100644 ast/while_stmt.go create mode 100644 ast/while_stmt_test.go create mode 100644 main.go create mode 100644 objc/main.m create mode 100644 wrap/main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6bb4b82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +clast +ast.txt + diff --git a/ast/aligned_attr.go b/ast/aligned_attr.go new file mode 100644 index 0000000..64c05d3 --- /dev/null +++ b/ast/aligned_attr.go @@ -0,0 +1,47 @@ +package ast + +// AlignedAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type AlignedAttr struct { + Addr Address + Pos Position + IsAligned bool + ChildNodes []Node +} + +func parseAlignedAttr(line string) *AlignedAttr { + groups := groupsFromRegex( + "<(?P.*)>(?P aligned)?", + line, + ) + + return &AlignedAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + IsAligned: len(groups["aligned"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *AlignedAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *AlignedAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *AlignedAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *AlignedAttr) Position() Position { + return n.Pos +} diff --git a/ast/aligned_attr_test.go b/ast/aligned_attr_test.go new file mode 100644 index 0000000..17647c0 --- /dev/null +++ b/ast/aligned_attr_test.go @@ -0,0 +1,24 @@ +package ast + +import ( + "testing" +) + +func TestAlignedAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7f8a1d8ccfd0 aligned`: &AlignedAttr{ + Addr: 0x7f8a1d8ccfd0, + Pos: NewPositionFromString("col:47, col:57"), + IsAligned: true, + ChildNodes: []Node{}, + }, + `0x2c8ba10 `: &AlignedAttr{ + Addr: 0x2c8ba10, + Pos: NewPositionFromString("col:42"), + IsAligned: false, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/alloc_size_attr.go b/ast/alloc_size_attr.go new file mode 100644 index 0000000..5f7cbb2 --- /dev/null +++ b/ast/alloc_size_attr.go @@ -0,0 +1,57 @@ +package ast + +import ( + "strings" + + "github.com/elliotchance/c2go/util" +) + +// AllocSizeAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type AllocSizeAttr struct { + Addr Address + Pos Position + Inherited bool + A int + B int + ChildNodes []Node +} + +func parseAllocSizeAttr(line string) *AllocSizeAttr { + groups := groupsFromRegex( + `<(?P.*)>(?P Inherited)?(?P \d+)(?P \d+)?`, + line, + ) + + return &AllocSizeAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Inherited: len(groups["inherited"]) > 0, + A: util.Atoi(strings.TrimSpace(groups["a"])), + B: util.Atoi(strings.TrimSpace(groups["b"])), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *AllocSizeAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *AllocSizeAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *AllocSizeAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *AllocSizeAttr) Position() Position { + return n.Pos +} diff --git a/ast/alloc_size_attr_test.go b/ast/alloc_size_attr_test.go new file mode 100644 index 0000000..fa59835 --- /dev/null +++ b/ast/alloc_size_attr_test.go @@ -0,0 +1,27 @@ +package ast + +import ( + "testing" +) + +func TestAllocSizeAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7f8e390a5d38 1 2`: &AllocSizeAttr{ + Addr: 0x7f8e390a5d38, + Pos: NewPositionFromString("col:100, col:114"), + A: 1, + B: 2, + ChildNodes: []Node{}, + }, + `0x7fbd1a167f48 Inherited 1 0`: &AllocSizeAttr{ + Addr: 0x7fbd1a167f48, + Pos: NewPositionFromString("/usr/include/stdlib.h:342:37"), + Inherited: true, + A: 1, + B: 0, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/always_inline_attr.go b/ast/always_inline_attr.go new file mode 100644 index 0000000..d01c565 --- /dev/null +++ b/ast/always_inline_attr.go @@ -0,0 +1,45 @@ +package ast + +// AlwaysInlineAttr is a type of attribute that is optionally attached to a +// variable or struct field definition. +type AlwaysInlineAttr struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseAlwaysInlineAttr(line string) *AlwaysInlineAttr { + groups := groupsFromRegex( + "<(?P.*)> always_inline", + line, + ) + + return &AlwaysInlineAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *AlwaysInlineAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *AlwaysInlineAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *AlwaysInlineAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *AlwaysInlineAttr) Position() Position { + return n.Pos +} diff --git a/ast/always_inline_attr_test.go b/ast/always_inline_attr_test.go new file mode 100644 index 0000000..5c0bd91 --- /dev/null +++ b/ast/always_inline_attr_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestAlwaysInlineAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fce780f5018 always_inline`: &AlwaysInlineAttr{ + Addr: 0x7fce780f5018, + Pos: NewPositionFromString("/usr/include/sys/cdefs.h:313:68"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/array_filler.go b/ast/array_filler.go new file mode 100644 index 0000000..44ae605 --- /dev/null +++ b/ast/array_filler.go @@ -0,0 +1,36 @@ +package ast + +// ArrayFiller is type of array filler +type ArrayFiller struct { + ChildNodes []Node +} + +func parseArrayFiller(line string) *ArrayFiller { + return &ArrayFiller{ + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ArrayFiller) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. For an ArrayFilter this will +// always be zero. See the documentation for the Address type for more +// information. +func (n *ArrayFiller) Address() Address { + return 0 +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ArrayFiller) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ArrayFiller) Position() Position { + return Position{} +} diff --git a/ast/array_filler_test.go b/ast/array_filler_test.go new file mode 100644 index 0000000..30d7a3e --- /dev/null +++ b/ast/array_filler_test.go @@ -0,0 +1,20 @@ +package ast + +import ( + "reflect" + "testing" + + "github.com/elliotchance/c2go/util" +) + +func TestArrayFiller(t *testing.T) { + expected := &ArrayFiller{ + ChildNodes: []Node{}, + } + actual := Parse(`array filler`) + + if !reflect.DeepEqual(expected, actual) { + t.Errorf("%s", util.ShowDiff(formatMultiLine(expected), + formatMultiLine(actual))) + } +} diff --git a/ast/array_subscript_expr.go b/ast/array_subscript_expr.go new file mode 100644 index 0000000..03c818b --- /dev/null +++ b/ast/array_subscript_expr.go @@ -0,0 +1,54 @@ +package ast + +// ArraySubscriptExpr is expression. +type ArraySubscriptExpr struct { + Addr Address + Pos Position + Type string + Type2 string + IsLvalue bool + IsVectorComponent bool + ChildNodes []Node +} + +func parseArraySubscriptExpr(line string) *ArraySubscriptExpr { + groups := groupsFromRegex( + `<(?P.*)> '(?P.*?)'(:'(?P.*?)')? + (?P lvalue)? + (?P vectorcomponent)?`, + line, + ) + + return &ArraySubscriptExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Type2: groups["type2"], + IsLvalue: len(groups["lvalue"]) > 0, + IsVectorComponent: len(groups["vcomp"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ArraySubscriptExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ArraySubscriptExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ArraySubscriptExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ArraySubscriptExpr) Position() Position { + return n.Pos +} diff --git a/ast/array_subscript_expr_test.go b/ast/array_subscript_expr_test.go new file mode 100644 index 0000000..5f44020 --- /dev/null +++ b/ast/array_subscript_expr_test.go @@ -0,0 +1,36 @@ +package ast + +import ( + "testing" +) + +func TestArraySubscriptExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7fe35b85d180 'char *' lvalue`: &ArraySubscriptExpr{ + Addr: 0x7fe35b85d180, + Pos: NewPositionFromString("col:63, col:69"), + Type: "char *", + Type2: "", + IsLvalue: true, + ChildNodes: []Node{}, + }, + `0x2416660 'u32':'unsigned int' lvalue`: &ArraySubscriptExpr{ + Addr: 0x2416660, + Pos: NewPositionFromString("col:2, col:5"), + Type: "u32", + Type2: "unsigned int", + IsLvalue: true, + ChildNodes: []Node{}, + }, + `0x3f147c0 'extCoord':'extCoord' lvalue`: &ArraySubscriptExpr{ + Addr: 0x3f147c0, + Pos: NewPositionFromString("col:39, col:55"), + Type: "extCoord", + Type2: "extCoord", + IsLvalue: true, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/asm_label_attr.go b/ast/asm_label_attr.go new file mode 100644 index 0000000..81566d5 --- /dev/null +++ b/ast/asm_label_attr.go @@ -0,0 +1,50 @@ +package ast + +// AsmLabelAttr is a type of attribute for assembler label +type AsmLabelAttr struct { + Addr Address + Pos Position + Inherited bool + FunctionName string + ChildNodes []Node +} + +func parseAsmLabelAttr(line string) *AsmLabelAttr { + groups := groupsFromRegex( + `<(?P.*)> + (?P Inherited)? + "(?P.+)"`, + line, + ) + + return &AsmLabelAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Inherited: len(groups["inherited"]) > 0, + FunctionName: groups["function"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *AsmLabelAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *AsmLabelAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *AsmLabelAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *AsmLabelAttr) Position() Position { + return n.Pos +} diff --git a/ast/asm_label_attr_test.go b/ast/asm_label_attr_test.go new file mode 100644 index 0000000..83775c9 --- /dev/null +++ b/ast/asm_label_attr_test.go @@ -0,0 +1,26 @@ +package ast + +import ( + "testing" +) + +func TestAsmLabelAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7ff26d8224e8 "_fopen"`: &AsmLabelAttr{ + Addr: 0x7ff26d8224e8, + Pos: NewPositionFromString("/usr/include/sys/cdefs.h:569:36"), + Inherited: false, + FunctionName: "_fopen", + ChildNodes: []Node{}, + }, + `0x7fd55a169318 Inherited "_popen"`: &AsmLabelAttr{ + Addr: 0x7fd55a169318, + Pos: NewPositionFromString("/usr/include/stdio.h:325:47"), + Inherited: true, + FunctionName: "_popen", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/ast.go b/ast/ast.go new file mode 100644 index 0000000..b955d7a --- /dev/null +++ b/ast/ast.go @@ -0,0 +1,323 @@ +// Package ast parses the clang AST output into AST structures. +package ast + +import ( + "strconv" + "strings" + + "github.com/elliotchance/c2go/util" +) + +// Node represents any node in the AST. +type Node interface { + Address() Address + Children() []Node + AddChild(node Node) + Position() Position +} + +// Address contains the memory address (originally outputted as a hexadecimal +// string) from the clang AST. The address are not predictable between run and +// are only useful for identifying nodes in a single AST. +// +// The Address is used like a primary key when storing the tree as a flat +// structure. +type Address uint64 + +// ParseAddress returns the integer representation of the hexadecimal address +// (like 0x7f8a1d8ccfd0). If the address cannot be parsed, 0 is returned. +func ParseAddress(address string) Address { + addr, _ := strconv.ParseUint(address, 0, 64) + + return Address(addr) +} + +// Parse takes the coloured output of the clang AST command and returns a root +// node for the AST. +func Parse(fullline string) Node { + line := fullline + + // This is a special case. I'm not sure if it's a bug in the clang AST + // dumper. It should have children. + if line == "array filler" { + return parseArrayFiller(line) + } + + parts := strings.SplitN(line, " ", 2) + nodeName := parts[0] + + if nodeName == "super" || nodeName == "getter" { // special ObjC case + parts = strings.SplitN(parts[1], " ", 2) + nodeName += " " + parts[0] + } + // skip node name + if len(parts) > 1 { + line = parts[1] + } + + switch nodeName { + case "AlignedAttr": + return parseAlignedAttr(line) + case "AllocSizeAttr": + return parseAllocSizeAttr(line) + case "AlwaysInlineAttr": + return parseAlwaysInlineAttr(line) + case "ArraySubscriptExpr": + return parseArraySubscriptExpr(line) + case "AsmLabelAttr": + return parseAsmLabelAttr(line) + case "AttributedType": + return parseAttributedType(line) + case "AvailabilityAttr": + return parseAvailabilityAttr(line) + case "BinaryOperator": + return parseBinaryOperator(line) + case "BlockCommandComment": + return parseBlockCommandComment(line) + case "BlockPointerType": + return parseBlockPointerType(line) + case "BreakStmt": + return parseBreakStmt(line) + case "BuiltinType": + return parseBuiltinType(line) + case "CallExpr": + return parseCallExpr(line) + case "CaseStmt": + return parseCaseStmt(line) + case "CharacterLiteral": + return parseCharacterLiteral(line) + case "CompoundLiteralExpr": + return parseCompoundLiteralExpr(line) + case "CompoundStmt": + return parseCompoundStmt(line) + case "ConditionalOperator": + return parseConditionalOperator(line) + case "ConstAttr": + return parseConstAttr(line) + case "ConstantArrayType": + return parseConstantArrayType(line) + case "ContinueStmt": + return parseContinueStmt(line) + case "CompoundAssignOperator": + return parseCompoundAssignOperator(line) + case "CStyleCastExpr": + return parseCStyleCastExpr(line) + case "DeclRefExpr": + return parseDeclRefExpr(line) + case "DeclStmt": + return parseDeclStmt(line) + case "DefaultStmt": + return parseDefaultStmt(line) + case "DeprecatedAttr": + return parseDeprecatedAttr(line) + case "DisableTailCallsAttr": + return parseDisableTailCallsAttr(line) + case "DoStmt": + return parseDoStmt(line) + case "ElaboratedType": + return parseElaboratedType(line) + case "EmptyDecl": + return parseEmptyDecl(line) + case "Enum": + return parseEnum(line) + case "EnumConstantDecl": + return parseEnumConstantDecl(line) + case "EnumDecl": + return parseEnumDecl(line) + case "EnumType": + return parseEnumType(line) + case "Field": + return parseField(line) + case "FieldDecl": + return parseFieldDecl(line) + case "FloatingLiteral": + return parseFloatingLiteral(line) + case "FormatAttr": + return parseFormatAttr(line) + case "FormatArgAttr": + return parseFormatArgAttr(line) + case "FunctionDecl": + return parseFunctionDecl(line) + case "FullComment": + return parseFullComment(line) + case "FunctionProtoType": + return parseFunctionProtoType(line) + case "ForStmt": + return parseForStmt(line) + case "HTMLStartTagComment": + return parseHTMLStartTagComment(line) + case "HTMLEndTagComment": + return parseHTMLEndTagComment(line) + case "GCCAsmStmt": + return parseGCCAsmStmt(line) + case "GotoStmt": + return parseGotoStmt(line) + case "IfStmt": + return parseIfStmt(line) + case "ImplicitCastExpr": + return parseImplicitCastExpr(line) + case "ImplicitValueInitExpr": + return parseImplicitValueInitExpr(line) + case "IncompleteArrayType": + return parseIncompleteArrayType(line) + case "IndirectFieldDecl": + return parseIndirectFieldDecl(line) + case "InitListExpr": + return parseInitListExpr(line) + case "InlineCommandComment": + return parseInlineCommandComment(line) + case "IntegerLiteral": + return parseIntegerLiteral(line) + case "LabelStmt": + return parseLabelStmt(line) + case "MallocAttr": + return parseMallocAttr(line) + case "MaxFieldAlignmentAttr": + return parseMaxFieldAlignmentAttr(line) + case "MemberExpr": + return parseMemberExpr(line) + case "ModeAttr": + return parseModeAttr(line) + case "NoInlineAttr": + return parseNoInlineAttr(line) + case "NoThrowAttr": + return parseNoThrowAttr(line) + case "NonNullAttr": + return parseNonNullAttr(line) + case "NotTailCalledAttr": + return parseNotTailCalledAttr(line) + case "ObjCInterface": + return parseObjCInterface(line) + case "ObjCInterfaceType": + return parseObjCInterfaceType(line) + case "super ObjCInterface": + return parseObjCInterface(line) + case "ObjCInterfaceDecl": + return parseObjCInterfaceDecl(line) + case "getter ObjCMethod": + return parseObjCMethod(line) + case "ObjCMethod": + return parseObjCMethod(line) + case "ObjCMethodDecl": + return parseObjCMethodDecl(line) + case "ObjCObjectType": + return parseObjCObjectType(line) + case "ObjCObjectPointerType": + return parseObjCObjectPointerType(line) + case "ObjCProtocol": + return parseObjCProtocol(line) + case "OffsetOfExpr": + return parseOffsetOfExpr(line) + case "PackedAttr": + return parsePackedAttr(line) + case "ParagraphComment": + return parseParagraphComment(line) + case "ParamCommandComment": + return parseParamCommandComment(line) + case "ParenExpr": + return parseParenExpr(line) + case "ParenType": + return parseParenType(line) + case "ParmVarDecl": + return parseParmVarDecl(line) + case "PointerType": + return parsePointerType(line) + case "DecayedType": + return parseDecayedType(line) + case "PredefinedExpr": + return parsePredefinedExpr(line) + case "PureAttr": + return parsePureAttr(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 "ReturnsTwiceAttr": + return parseReturnsTwiceAttr(line) + case "SentinelAttr": + return parseSentinelAttr(line) + case "StmtExpr": + return parseStmtExpr(line) + case "StringLiteral": + return parseStringLiteral(line) + case "SwitchStmt": + return parseSwitchStmt(line) + case "TextComment": + return parseTextComment(line) + case "TranslationUnitDecl": + return parseTranslationUnitDecl(line) + case "TransparentUnionAttr": + return parseTransparentUnionAttr(line) + case "Typedef": + return parseTypedef(line) + case "TypedefDecl": + return parseTypedefDecl(line) + case "TypedefType": + return parseTypedefType(line) + case "UnaryExprOrTypeTraitExpr": + return parseUnaryExprOrTypeTraitExpr(line) + case "UnaryOperator": + return parseUnaryOperator(line) + case "UnusedAttr": + return parseUnusedAttr(line) + case "VAArgExpr": + return parseVAArgExpr(line) + case "VarDecl": + return parseVarDecl(line) + case "VectorType": + return parseVectorType(line) + case "VerbatimBlockComment": + return parseVerbatimBlockComment(line) + case "VerbatimBlockLineComment": + return parseVerbatimBlockLineComment(line) + case "VerbatimLineComment": + return parseVerbatimLineComment(line) + case "VisibilityAttr": + return parseVisibilityAttr(line) + case "WarnUnusedResultAttr": + return parseWarnUnusedResultAttr(line) + case "WeakAttr": + return parseWeakAttr(line) + case "WhileStmt": + return parseWhileStmt(line) + case "NullStmt": + return nil + case "...": // FIXME for variadic functions + return nil + default: + return parseUnknown(nodeName,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) + rx = fullRegexp + "[\\s]*$" + + re := util.GetRegex(rx) + + match := re.FindStringSubmatch(line) + if len(match) == 0 { + panic("could not match regexp with string\n" + rx + "\n" + line + "\n") + } + + result := make(map[string]string) + for i, name := range re.SubexpNames() { + if i != 0 { + result[name] = match[i] + } + } + + return result +} diff --git a/ast/ast_test.go b/ast/ast_test.go new file mode 100644 index 0000000..0a80547 --- /dev/null +++ b/ast/ast_test.go @@ -0,0 +1,70 @@ +package ast + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "github.com/elliotchance/c2go/util" +) + +func formatMultiLine(o interface{}) string { + s := fmt.Sprintf("%#v", o) + s = strings.Replace(s, "{", "{\n", -1) + s = strings.Replace(s, ", ", "\n", -1) + + return s +} + +func runNodeTests(t *testing.T, tests map[string]Node) { + i := 1 + for line, expected := range tests { + testName := fmt.Sprintf("Example%d", i) + i++ + + t.Run(testName, func(t *testing.T) { + // Append the name of the struct onto the front. This would make the + // complete line it would normally be parsing. + name := reflect.TypeOf(expected).Elem().Name() + actual := Parse(name + " " + line) + + if !reflect.DeepEqual(expected, actual) { + t.Errorf("%s", util.ShowDiff(formatMultiLine(expected), + formatMultiLine(actual))) + } + }) + } +} + +func TestPrint(t *testing.T) { + cond := &ConditionalOperator{} + cond.AddChild(&ImplicitCastExpr{}) + cond.AddChild(&ImplicitCastExpr{}) + s := Atos(cond) + if len(s) == 0 { + t.Fatalf("Cannot convert AST tree : %#v", cond) + } + lines := strings.Split(s, "\n") + var amount int + for _, l := range lines { + if strings.Contains(l, "ImplicitCastExpr") { + amount++ + } + } + if amount != 2 { + t.Error("Not correct design of output") + } +} + +var lines = []string{ +// c2go ast sqlite3.c | head -5000 | sed 's/^[ |`-]*//' | sed 's/<<>>/NullStmt/g' | gawk 'length > 0 {print "`" $0 "`,"}' +} + +func BenchmarkParse(b *testing.B) { + for n := 0; n < b.N; n++ { + for _, line := range lines { + Parse(line) + } + } +} diff --git a/ast/attributed_type.go b/ast/attributed_type.go new file mode 100644 index 0000000..c8e6ff4 --- /dev/null +++ b/ast/attributed_type.go @@ -0,0 +1,47 @@ +package ast + +// AttributedType is attributed type +type AttributedType struct { + Addr Address + Type string + Sugar bool + ChildNodes []Node +} + +func parseAttributedType(line string) *AttributedType { + groups := groupsFromRegex( + `'(?P.*)' + (?P sugar)?`, + line, + ) + + return &AttributedType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + Sugar: len(groups["sugar"])>0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *AttributedType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *AttributedType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *AttributedType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *AttributedType) Position() Position { + return Position{} +} diff --git a/ast/availability_attr.go b/ast/availability_attr.go new file mode 100644 index 0000000..37b09f0 --- /dev/null +++ b/ast/availability_attr.go @@ -0,0 +1,69 @@ +package ast + +// AvailabilityAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type AvailabilityAttr struct { + Addr Address + Pos Position + OS string + Version string + Unknown1 string + Unknown2 string + IsUnavailable bool + Message1 string + Message2 string + IsInherited bool + ChildNodes []Node +} + +func parseAvailabilityAttr(line string) *AvailabilityAttr { + groups := groupsFromRegex( + `<(?P.*)> + (?P Inherited)? + (?P\w+) + (?P[\d_.]+) + (?P[\d_.]+) + (?P[\d_.]+) + (?P Unavailable)? + "(?P.*?)" + (?P ".*?")?`, + line, + ) + + return &AvailabilityAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + OS: groups["os"], + Version: groups["version"], + Unknown1: groups["unknown1"], + Unknown2: groups["unknown2"], + IsUnavailable: len(groups["unavalable"]) > 0, + Message1: removeQuotes(groups["message1"]), + Message2: removeQuotes(groups["message2"]), + IsInherited: len(groups["inherited"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *AvailabilityAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *AvailabilityAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *AvailabilityAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *AvailabilityAttr) Position() Position { + return n.Pos +} diff --git a/ast/availability_attr_test.go b/ast/availability_attr_test.go new file mode 100644 index 0000000..ab6dee6 --- /dev/null +++ b/ast/availability_attr_test.go @@ -0,0 +1,116 @@ +package ast + +import ( + "testing" +) + +func TestAvailabilityAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fc5ff8e5d18 macos 10.10 0 0 "" ""`: &AvailabilityAttr{ + Addr: 0x7fc5ff8e5d18, + Pos: NewPositionFromString("/usr/include/AvailabilityInternal.h:21697:88, col:124"), + OS: "macos", + Version: "10.10", + Unknown1: 0, + Unknown2: 0, + IsUnavailable: false, + Message1: "", + Message2: "", + IsInherited: false, + ChildNodes: []Node{}, + }, + `0x7fc5ff8e60d0 watchos 3.0 0 0 "" ""`: &AvailabilityAttr{ + Addr: 0x7fc5ff8e60d0, + Pos: NewPositionFromString("/usr/include/Availability.h:215:81, col:115"), + OS: "watchos", + Version: "3.0", + Unknown1: 0, + Unknown2: 0, + IsUnavailable: false, + Message1: "", + Message2: "", + IsInherited: false, + ChildNodes: []Node{}, + }, + `0x7fc5ff8e6170 tvos 10.0 0 0 "" ""`: &AvailabilityAttr{ + Addr: 0x7fc5ff8e6170, + Pos: NewPositionFromString("col:81, col:115"), + OS: "tvos", + Version: "10.0", + Unknown1: 0, + Unknown2: 0, + IsUnavailable: false, + Message1: "", + Message2: "", + IsInherited: false, + ChildNodes: []Node{}, + }, + `0x7fc5ff8e61d8 ios 10.0 0 0 "" ""`: &AvailabilityAttr{ + Addr: 0x7fc5ff8e61d8, + Pos: NewPositionFromString("col:81, col:115"), + OS: "ios", + Version: "10.0", + Unknown1: 0, + Unknown2: 0, + IsUnavailable: false, + Message1: "", + Message2: "", + IsInherited: false, + ChildNodes: []Node{}, + }, + `0x7fc5ff8f0e18 swift 0 0 0 Unavailable "Use snprintf instead." ""`: &AvailabilityAttr{ + Addr: 0x7fc5ff8f0e18, + Pos: NewPositionFromString("/usr/include/sys/cdefs.h:275:50, col:99"), + OS: "swift", + Version: "0", + Unknown1: 0, + Unknown2: 0, + IsUnavailable: true, + Message1: "Use snprintf instead.", + Message2: "", + IsInherited: false, + ChildNodes: []Node{}, + }, + `0x7fc5ff8f1988 swift 0 0 0 Unavailable "Use mkstemp(3) instead." ""`: &AvailabilityAttr{ + Addr: 0x7fc5ff8f1988, + Pos: NewPositionFromString("line:275:50, col:99"), + OS: "swift", + Version: "0", + Unknown1: 0, + Unknown2: 0, + IsUnavailable: true, + Message1: "Use mkstemp(3) instead.", + Message2: "", + IsInherited: false, + ChildNodes: []Node{}, + }, + `0x104035438 macosx 10.10 0 0 ""`: &AvailabilityAttr{ + Addr: 0x104035438, + Pos: NewPositionFromString("/usr/include/AvailabilityInternal.h:14571:88, col:124"), + OS: "macosx", + Version: "10.10", + Unknown1: 0, + Unknown2: 0, + IsUnavailable: false, + Message1: "", + Message2: "", + IsInherited: false, + ChildNodes: []Node{}, + }, + `0x7f9bd588b1a8 Inherited macos 10.5 0 0 "" ""`: &AvailabilityAttr{ + Addr: 0x7f9bd588b1a8, + Pos: NewPositionFromString("/usr/include/gethostuuid.h:39:65, col:100"), + OS: "macos", + Version: "10.5", + Unknown1: 0, + Unknown2: 0, + IsUnavailable: false, + Message1: "", + Message2: "", + IsInherited: true, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/binary_operator.go b/ast/binary_operator.go new file mode 100644 index 0000000..a1d894b --- /dev/null +++ b/ast/binary_operator.go @@ -0,0 +1,50 @@ +package ast + +// BinaryOperator is type of binary operator +type BinaryOperator struct { + Addr Address + Pos Position + Type string + Type2 string + Operator string + ChildNodes []Node +} + +func parseBinaryOperator(line string) *BinaryOperator { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*?)'(:'(?P.*?)')? '(?P.*?)'", + line, + ) + + return &BinaryOperator{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type1"], + Type2: groups["type2"], + Operator: groups["operator"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *BinaryOperator) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *BinaryOperator) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *BinaryOperator) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *BinaryOperator) Position() Position { + return n.Pos +} diff --git a/ast/binary_operator_test.go b/ast/binary_operator_test.go new file mode 100644 index 0000000..f965650 --- /dev/null +++ b/ast/binary_operator_test.go @@ -0,0 +1,27 @@ +package ast + +import ( + "testing" +) + +func TestBinaryOperator(t *testing.T) { + nodes := map[string]Node{ + `0x7fca2d8070e0 'unsigned char' '='`: &BinaryOperator{ + Addr: 0x7fca2d8070e0, + Pos: NewPositionFromString("col:11, col:23"), + Type: "unsigned char", + Operator: "=", + ChildNodes: []Node{}, + }, + `0x1ff95b8 'T_ENUM':'T_ENUM' '='`: &BinaryOperator{ + Addr: 0x1ff95b8, + Pos: NewPositionFromString("line:78:2, col:7"), + Type: "T_ENUM", + Type2: "T_ENUM", + Operator: "=", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/block_command_comment.go b/ast/block_command_comment.go new file mode 100644 index 0000000..557517e --- /dev/null +++ b/ast/block_command_comment.go @@ -0,0 +1,46 @@ +package ast + +// BlockCommandComment is a type of comment +type BlockCommandComment struct { + Addr Address + Pos Position + Name string + ChildNodes []Node +} + +func parseBlockCommandComment(line string) *BlockCommandComment { + groups := groupsFromRegex( + `<(?P.*)> Name="(?P.*)"`, + line, + ) + + return &BlockCommandComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Name: groups["name"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *BlockCommandComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *BlockCommandComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *BlockCommandComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *BlockCommandComment) Position() Position { + return n.Pos +} diff --git a/ast/block_command_comment_test.go b/ast/block_command_comment_test.go new file mode 100644 index 0000000..cb86ba8 --- /dev/null +++ b/ast/block_command_comment_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestBlockCommandComment(t *testing.T) { + nodes := map[string]Node{ + `0x1069fae60 Name="abstract"`: &BlockCommandComment{ + Addr: 0x1069fae60, + Pos: NewPositionFromString("col:4, line:163:57"), + Name: "abstract", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/block_pointer_type.go b/ast/block_pointer_type.go new file mode 100644 index 0000000..0a66c1b --- /dev/null +++ b/ast/block_pointer_type.go @@ -0,0 +1,44 @@ +package ast + +// BlockPointerType is block pointer type +type BlockPointerType struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseBlockPointerType(line string) *BlockPointerType { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &BlockPointerType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *BlockPointerType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *BlockPointerType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *BlockPointerType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *BlockPointerType) Position() Position { + return Position{} +} diff --git a/ast/break_stmt.go b/ast/break_stmt.go new file mode 100644 index 0000000..bf99971 --- /dev/null +++ b/ast/break_stmt.go @@ -0,0 +1,44 @@ +package ast + +// BreakStmt is node represent 'break' +type BreakStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseBreakStmt(line string) *BreakStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &BreakStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *BreakStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *BreakStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *BreakStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *BreakStmt) Position() Position { + return n.Pos +} diff --git a/ast/break_stmt_test.go b/ast/break_stmt_test.go new file mode 100644 index 0000000..3c2cace --- /dev/null +++ b/ast/break_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestBreakStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fca2d8070e0 `: &BreakStmt{ + Addr: 0x7fca2d8070e0, + Pos: NewPositionFromString("col:11, col:23"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/builtin_type.go b/ast/builtin_type.go new file mode 100644 index 0000000..6bd4cbd --- /dev/null +++ b/ast/builtin_type.go @@ -0,0 +1,44 @@ +package ast + +// BuiltinType is builtin type +type BuiltinType struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseBuiltinType(line string) *BuiltinType { + groups := groupsFromRegex( + "'(?P.*?)'", + line, + ) + + return &BuiltinType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *BuiltinType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *BuiltinType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *BuiltinType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *BuiltinType) Position() Position { + return Position{} +} diff --git a/ast/builtin_type_test.go b/ast/builtin_type_test.go new file mode 100644 index 0000000..60768fd --- /dev/null +++ b/ast/builtin_type_test.go @@ -0,0 +1,22 @@ +package ast + +import ( + "testing" +) + +func TestBuiltinType(t *testing.T) { + nodes := map[string]Node{ + `0x7f8a43023f40 '__int128'`: &BuiltinType{ + Addr: 0x7f8a43023f40, + Type: "__int128", + ChildNodes: []Node{}, + }, + `0x7f8a43023ea0 'unsigned long long'`: &BuiltinType{ + Addr: 0x7f8a43023ea0, + Type: "unsigned long long", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/c_style_cast_expr.go b/ast/c_style_cast_expr.go new file mode 100644 index 0000000..49658ea --- /dev/null +++ b/ast/c_style_cast_expr.go @@ -0,0 +1,56 @@ +package ast + +// CStyleCastExpr is expression. +type CStyleCastExpr struct { + Addr Address + Pos Position + Type string + Type2 string + Kind string + ChildNodes []Node +} + +// CStyleCastExprNullToPointer - string of kind NullToPointer +var CStyleCastExprNullToPointer = "NullToPointer" + +// CStyleCastExprToVoid - string of kind ToVoid +var CStyleCastExprToVoid = "ToVoid" + +func parseCStyleCastExpr(line string) *CStyleCastExpr { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*?)'(:'(?P.*?)')? <(?P.*)>", + line, + ) + + return &CStyleCastExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type1"], + Type2: groups["type2"], + Kind: groups["kind"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *CStyleCastExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *CStyleCastExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *CStyleCastExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *CStyleCastExpr) Position() Position { + return n.Pos +} diff --git a/ast/c_style_cast_expr_test.go b/ast/c_style_cast_expr_test.go new file mode 100644 index 0000000..2745e90 --- /dev/null +++ b/ast/c_style_cast_expr_test.go @@ -0,0 +1,27 @@ +package ast + +import ( + "testing" +) + +func TestCStyleCastExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7fddc18fb2e0 'char' `: &CStyleCastExpr{ + Addr: 0x7fddc18fb2e0, + Pos: NewPositionFromString("col:50, col:56"), + Type: "char", + Kind: "IntegralCast", + ChildNodes: []Node{}, + }, + `0x2781518 'T_ENUM':'T_ENUM' `: &CStyleCastExpr{ + Addr: 0x2781518, + Pos: NewPositionFromString("col:7, col:17"), + Type: "T_ENUM", + Type2: "T_ENUM", + Kind: "IntegralCast", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/call_expr.go b/ast/call_expr.go new file mode 100644 index 0000000..c71d684 --- /dev/null +++ b/ast/call_expr.go @@ -0,0 +1,46 @@ +package ast + +// CallExpr is expression. +type CallExpr struct { + Addr Address + Pos Position + Type string + ChildNodes []Node +} + +func parseCallExpr(line string) *CallExpr { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*?)'", + line, + ) + + return &CallExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *CallExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *CallExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *CallExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *CallExpr) Position() Position { + return n.Pos +} diff --git a/ast/call_expr_test.go b/ast/call_expr_test.go new file mode 100644 index 0000000..b8aeae1 --- /dev/null +++ b/ast/call_expr_test.go @@ -0,0 +1,24 @@ +package ast + +import ( + "testing" +) + +func TestCallExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7f9bf3033240 'int'`: &CallExpr{ + Addr: 0x7f9bf3033240, + Pos: NewPositionFromString("col:11, col:25"), + Type: "int", + ChildNodes: []Node{}, + }, + `0x7f9bf3035c20 'int'`: &CallExpr{ + Addr: 0x7f9bf3035c20, + Pos: NewPositionFromString("line:7:4, col:64"), + Type: "int", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/case_stmt.go b/ast/case_stmt.go new file mode 100644 index 0000000..ba86c42 --- /dev/null +++ b/ast/case_stmt.go @@ -0,0 +1,41 @@ +package ast + +// CaseStmt is node represent 'case' +type CaseStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseCaseStmt(line string) *CaseStmt { + groups := groupsFromRegex(`<(?P.*)>`, line) + + return &CaseStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *CaseStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *CaseStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *CaseStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *CaseStmt) Position() Position { + return n.Pos +} diff --git a/ast/case_stmt_test.go b/ast/case_stmt_test.go new file mode 100644 index 0000000..ea24a74 --- /dev/null +++ b/ast/case_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestCaseStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fc8b5094688 `: &CaseStmt{ + Addr: 0x7fc8b5094688, + Pos: NewPositionFromString("line:11:5, line:12:21"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/character_literal.go b/ast/character_literal.go new file mode 100644 index 0000000..403d2c2 --- /dev/null +++ b/ast/character_literal.go @@ -0,0 +1,52 @@ +package ast + +import ( + "github.com/elliotchance/c2go/util" +) + +// CharacterLiteral is type of character literal +type CharacterLiteral struct { + Addr Address + Pos Position + Type string + Value int + ChildNodes []Node +} + +func parseCharacterLiteral(line string) *CharacterLiteral { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*?)' (?P\\d+)", + line, + ) + + return &CharacterLiteral{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Value: util.Atoi(groups["value"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *CharacterLiteral) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *CharacterLiteral) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *CharacterLiteral) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *CharacterLiteral) Position() Position { + return n.Pos +} diff --git a/ast/character_literal_test.go b/ast/character_literal_test.go new file mode 100644 index 0000000..00badcc --- /dev/null +++ b/ast/character_literal_test.go @@ -0,0 +1,19 @@ +package ast + +import ( + "testing" +) + +func TestCharacterLiteral(t *testing.T) { + nodes := map[string]Node{ + `0x7f980b858308 'int' 10`: &CharacterLiteral{ + Addr: 0x7f980b858308, + Pos: NewPositionFromString("col:62"), + Type: "int", + Value: 10, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/compound_assign_operator.go b/ast/compound_assign_operator.go new file mode 100644 index 0000000..d8e35ce --- /dev/null +++ b/ast/compound_assign_operator.go @@ -0,0 +1,56 @@ +package ast + +// CompoundAssignOperator is type of compound assign operator +type CompoundAssignOperator struct { + Addr Address + Pos Position + Type string + Opcode string + ComputationLHSType string + ComputationResultType string + ChildNodes []Node +} + +func parseCompoundAssignOperator(line string) *CompoundAssignOperator { + groups := groupsFromRegex( + `<(?P.*)> + '(?P.+?)' + '(?P.+?)' + ComputeLHSTy='(?P.+?)' + ComputeResultTy='(?P.+?)'`, + line, + ) + + return &CompoundAssignOperator{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Opcode: groups["opcode"], + ComputationLHSType: groups["clhstype"], + ComputationResultType: groups["crestype"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *CompoundAssignOperator) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *CompoundAssignOperator) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *CompoundAssignOperator) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *CompoundAssignOperator) Position() Position { + return n.Pos +} diff --git a/ast/compound_assign_operator_test.go b/ast/compound_assign_operator_test.go new file mode 100644 index 0000000..b7bed1a --- /dev/null +++ b/ast/compound_assign_operator_test.go @@ -0,0 +1,21 @@ +package ast + +import ( + "testing" +) + +func TestCompoundAssignOperator(t *testing.T) { + nodes := map[string]Node{ + `0x2dc5758 'int' '+=' ComputeLHSTy='int' ComputeResultTy='int'`: &CompoundAssignOperator{ + Addr: 0x2dc5758, + Pos: NewPositionFromString("line:5:2, col:7"), + Type: "int", + Opcode: "+=", + ComputationLHSType: "int", + ComputationResultType: "int", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/compound_literal_expr.go b/ast/compound_literal_expr.go new file mode 100644 index 0000000..ad86be3 --- /dev/null +++ b/ast/compound_literal_expr.go @@ -0,0 +1,48 @@ +package ast + +// CompoundLiteralExpr C99 6.5.2.5 +type CompoundLiteralExpr struct { + Addr Address + Pos Position + Type1 string + Type2 string + ChildNodes []Node +} + +func parseCompoundLiteralExpr(line string) *CompoundLiteralExpr { + groups := groupsFromRegex( + `<(?P.*)> '(?P.*?)'(:'(?P.*?)')? lvalue`, + line, + ) + + return &CompoundLiteralExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type1: groups["type1"], + Type2: groups["type2"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *CompoundLiteralExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *CompoundLiteralExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *CompoundLiteralExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *CompoundLiteralExpr) Position() Position { + return n.Pos +} diff --git a/ast/compound_literal_expr_test.go b/ast/compound_literal_expr_test.go new file mode 100644 index 0000000..4c89a90 --- /dev/null +++ b/ast/compound_literal_expr_test.go @@ -0,0 +1,19 @@ +package ast + +import ( + "testing" +) + +func TestCompoundLiteralExpr(t *testing.T) { + nodes := map[string]Node{ + `0x5575acce81f0 'struct node':'struct node' lvalue`: &CompoundLiteralExpr{ + Addr: 0x5575acce81f0, + Pos: NewPositionFromString("col:21, col:40"), + Type1: "struct node", + Type2: "struct node", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/compound_stmt.go b/ast/compound_stmt.go new file mode 100644 index 0000000..c588bcc --- /dev/null +++ b/ast/compound_stmt.go @@ -0,0 +1,48 @@ +package ast + +// CompoundStmt is node represents a compound of nodes +type CompoundStmt struct { + Addr Address + Pos Position + ChildNodes []Node + + // TODO: remove this + BelongsToSwitch bool +} + +func parseCompoundStmt(line string) *CompoundStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &CompoundStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + BelongsToSwitch: false, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *CompoundStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *CompoundStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *CompoundStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *CompoundStmt) Position() Position { + return n.Pos +} diff --git a/ast/compound_stmt_test.go b/ast/compound_stmt_test.go new file mode 100644 index 0000000..8ddd74b --- /dev/null +++ b/ast/compound_stmt_test.go @@ -0,0 +1,22 @@ +package ast + +import ( + "testing" +) + +func TestCompoundStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fbd0f014f18 `: &CompoundStmt{ + Addr: 0x7fbd0f014f18, + Pos: NewPositionFromString("col:54, line:358:1"), + ChildNodes: []Node{}, + }, + `0x7fbd0f8360b8 `: &CompoundStmt{ + Addr: 0x7fbd0f8360b8, + Pos: NewPositionFromString("line:4:1, line:13:1"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/conditional_operator.go b/ast/conditional_operator.go new file mode 100644 index 0000000..7b097e0 --- /dev/null +++ b/ast/conditional_operator.go @@ -0,0 +1,46 @@ +package ast + +// ConditionalOperator is type of condition operator +type ConditionalOperator struct { + Addr Address + Pos Position + Type string + ChildNodes []Node +} + +func parseConditionalOperator(line string) *ConditionalOperator { + groups := groupsFromRegex( + `<(?P.*)> '(?P.*?)'`, + line, + ) + + return &ConditionalOperator{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ConditionalOperator) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ConditionalOperator) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ConditionalOperator) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ConditionalOperator) Position() Position { + return n.Pos +} diff --git a/ast/conditional_operator_test.go b/ast/conditional_operator_test.go new file mode 100644 index 0000000..346d9c5 --- /dev/null +++ b/ast/conditional_operator_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestConditionalOperator(t *testing.T) { + nodes := map[string]Node{ + `0x7fc6ae0bc678 'void'`: &ConditionalOperator{ + Addr: 0x7fc6ae0bc678, + Pos: NewPositionFromString("col:6, col:89"), + Type: "void", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/const_attr.go b/ast/const_attr.go new file mode 100644 index 0000000..54509fd --- /dev/null +++ b/ast/const_attr.go @@ -0,0 +1,47 @@ +package ast + +// ConstAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type ConstAttr struct { + Addr Address + Pos Position + Tags string + ChildNodes []Node +} + +func parseConstAttr(line string) *ConstAttr { + groups := groupsFromRegex( + "<(?P.*)>(?P.*)", + line, + ) + + return &ConstAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Tags: groups["tags"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ConstAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ConstAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ConstAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ConstAttr) Position() Position { + return n.Pos +} diff --git a/ast/const_attr_test.go b/ast/const_attr_test.go new file mode 100644 index 0000000..74379d8 --- /dev/null +++ b/ast/const_attr_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestConstAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fa3b88bbb38 foo`: &ConstAttr{ + Addr: 0x7fa3b88bbb38, + Pos: NewPositionFromString("line:4:1, line:13:1"), + Tags: "foo", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/constant_array_type.go b/ast/constant_array_type.go new file mode 100644 index 0000000..ba4ff0f --- /dev/null +++ b/ast/constant_array_type.go @@ -0,0 +1,50 @@ +package ast + +import ( + "github.com/elliotchance/c2go/util" +) + +// ConstantArrayType is constant array type +type ConstantArrayType struct { + Addr Address + Type string + Size int + ChildNodes []Node +} + +func parseConstantArrayType(line string) *ConstantArrayType { + groups := groupsFromRegex( + "'(?P.*)' (?P\\d+)", + line, + ) + + return &ConstantArrayType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + Size: util.Atoi(groups["size"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ConstantArrayType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ConstantArrayType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ConstantArrayType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ConstantArrayType) Position() Position { + return Position{} +} diff --git a/ast/constant_array_type_test.go b/ast/constant_array_type_test.go new file mode 100644 index 0000000..10a97a9 --- /dev/null +++ b/ast/constant_array_type_test.go @@ -0,0 +1,24 @@ +package ast + +import ( + "testing" +) + +func TestConstantArrayType(t *testing.T) { + nodes := map[string]Node{ + `0x7f94ad016a40 'struct __va_list_tag [1]' 1 `: &ConstantArrayType{ + Addr: 0x7f94ad016a40, + Type: "struct __va_list_tag [1]", + Size: 1, + ChildNodes: []Node{}, + }, + `0x7f8c5f059d20 'char [37]' 37 `: &ConstantArrayType{ + Addr: 0x7f8c5f059d20, + Type: "char [37]", + Size: 37, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/continue_stmt.go b/ast/continue_stmt.go new file mode 100644 index 0000000..4a3decb --- /dev/null +++ b/ast/continue_stmt.go @@ -0,0 +1,44 @@ +package ast + +// ContinueStmt is node represent 'continue' +type ContinueStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseContinueStmt(line string) *ContinueStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &ContinueStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ContinueStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ContinueStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ContinueStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ContinueStmt) Position() Position { + return n.Pos +} diff --git a/ast/continue_stmt_test.go b/ast/continue_stmt_test.go new file mode 100644 index 0000000..d768349 --- /dev/null +++ b/ast/continue_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestContinueStmt(t *testing.T) { + nodes := map[string]Node{ + `0x1e044e0 `: &ContinueStmt{ + Addr: 0x1e044e0, + Pos: NewPositionFromString("col:20"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/decayed_type.go b/ast/decayed_type.go new file mode 100644 index 0000000..a19cfab --- /dev/null +++ b/ast/decayed_type.go @@ -0,0 +1,44 @@ +package ast + +// DecayedType is pointer type +type DecayedType struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseDecayedType(line string) *DecayedType { + groups := groupsFromRegex( + "'(?P.*)' sugar", + line, + ) + + return &DecayedType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *DecayedType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *DecayedType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *DecayedType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *DecayedType) Position() Position { + return Position{} +} diff --git a/ast/decayed_type_test.go b/ast/decayed_type_test.go new file mode 100644 index 0000000..e16c17d --- /dev/null +++ b/ast/decayed_type_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestDecayedType(t *testing.T) { + nodes := map[string]Node{ + `0x7f1234567890 'struct __va_list_tag *' sugar`: &DecayedType{ + Addr: 0x7f1234567890, + Type: "struct __va_list_tag *", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/decl_ref_expr.go b/ast/decl_ref_expr.go new file mode 100644 index 0000000..ffdeee3 --- /dev/null +++ b/ast/decl_ref_expr.go @@ -0,0 +1,71 @@ +package ast + +// DeclRefExpr is expression. +type DeclRefExpr struct { + Addr Address + Pos Position + Type string + Type1 string + Lvalue bool + For string + Address2 string + Name string + Type2 string + Type3 string + ChildNodes []Node +} + +func parseDeclRefExpr(line string) *DeclRefExpr { + groups := groupsFromRegex( + `<(?P.*)> + '(?P.*?)'(:'(?P.*?)')? + .*? + (?P lvalue)? + (?P\w+) + (?P[0-9a-fx]+) + '(?P.*?)' + '(?P.*?)'(:'(?P.*?)')? + `, + line, + ) + + return &DeclRefExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Type1: groups["type1"], + Lvalue: len(groups["lvalue"]) > 0, + For: groups["for"], + Address2: groups["address2"], + Name: groups["name"], + Type2: groups["type2"], + Type3: groups["type3"], + ChildNodes: []Node{}, + } +} + +// FunctionDeclRefExpr - value of DeclRefExpr.For for function +var FunctionDeclRefExpr = "Function" + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *DeclRefExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *DeclRefExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *DeclRefExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *DeclRefExpr) Position() Position { + return n.Pos +} diff --git a/ast/decl_ref_expr_test.go b/ast/decl_ref_expr_test.go new file mode 100644 index 0000000..2eedf5c --- /dev/null +++ b/ast/decl_ref_expr_test.go @@ -0,0 +1,77 @@ +package ast + +import ( + "testing" +) + +func TestDeclRefExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7fc972064460 'FILE *' lvalue ParmVar 0x7fc9720642d0 '_p' 'FILE *'`: &DeclRefExpr{ + Addr: 0x7fc972064460, + Pos: NewPositionFromString("col:8"), + Type: "FILE *", + Type1: "", + Lvalue: true, + For: "ParmVar", + Address2: "0x7fc9720642d0", + Name: "_p", + Type2: "FILE *", + Type3: "", + ChildNodes: []Node{}, + }, + `0x7fc97206a958 'int (int, FILE *)' Function 0x7fc972064198 '__swbuf' 'int (int, FILE *)'`: &DeclRefExpr{ + Addr: 0x7fc97206a958, + Pos: NewPositionFromString("col:11"), + Type: "int (int, FILE *)", + Type1: "", + Lvalue: false, + For: "Function", + Address2: "0x7fc972064198", + Name: "__swbuf", + Type2: "int (int, FILE *)", + Type3: "", + ChildNodes: []Node{}, + }, + `0x7fa36680f170 'struct programming':'struct programming' lvalue Var 0x7fa36680dc20 'variable' 'struct programming':'struct programming'`: &DeclRefExpr{ + Addr: 0x7fa36680f170, + Pos: NewPositionFromString("col:19"), + Type: "struct programming", + Type1: "struct programming", + Lvalue: true, + For: "Var", + Address2: "0x7fa36680dc20", + Name: "variable", + Type2: "struct programming", + Type3: "struct programming", + ChildNodes: []Node{}, + }, + `0x35cb438 'int' EnumConstant 0x35ca300 'Jan' 'int'`: &DeclRefExpr{ + Addr: 0x35cb438, + Pos: NewPositionFromString("col:13"), + Type: "int", + Type1: "", + Lvalue: false, + For: "EnumConstant", + Address2: "0x35ca300", + Name: "Jan", + Type2: "int", + Type3: "", + ChildNodes: []Node{}, + }, + `0x1ff8770 'T_ENUM':'T_ENUM' lvalue Var 0x1ff8600 'cc' 'T_ENUM':'T_ENUM'`: &DeclRefExpr{ + Addr: 0x1ff8770, + Pos: NewPositionFromString("col:33"), + Type: "T_ENUM", + Type1: "T_ENUM", + Lvalue: true, + For: "Var", + Address2: "0x1ff8600", + Name: "cc", + Type2: "T_ENUM", + Type3: "T_ENUM", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/decl_stmt.go b/ast/decl_stmt.go new file mode 100644 index 0000000..1312f34 --- /dev/null +++ b/ast/decl_stmt.go @@ -0,0 +1,44 @@ +package ast + +// DeclStmt is node represents a declaration in a statement list. +type DeclStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseDeclStmt(line string) *DeclStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &DeclStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *DeclStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *DeclStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *DeclStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *DeclStmt) Position() Position { + return n.Pos +} diff --git a/ast/decl_stmt_test.go b/ast/decl_stmt_test.go new file mode 100644 index 0000000..79ff721 --- /dev/null +++ b/ast/decl_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestDeclStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fb791846e80 `: &DeclStmt{ + Addr: 0x7fb791846e80, + Pos: NewPositionFromString("line:11:4, col:31"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/default_stmt.go b/ast/default_stmt.go new file mode 100644 index 0000000..e848852 --- /dev/null +++ b/ast/default_stmt.go @@ -0,0 +1,41 @@ +package ast + +// DefaultStmt is node represent 'default' +type DefaultStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseDefaultStmt(line string) *DefaultStmt { + groups := groupsFromRegex(`<(?P.*)>`, line) + + return &DefaultStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *DefaultStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *DefaultStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *DefaultStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *DefaultStmt) Position() Position { + return n.Pos +} diff --git a/ast/default_stmt_test.go b/ast/default_stmt_test.go new file mode 100644 index 0000000..3633862 --- /dev/null +++ b/ast/default_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestDefaultStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7f951308bfb0 `: &DefaultStmt{ + Addr: 0x7f951308bfb0, + Pos: NewPositionFromString("line:17:5, line:18:34"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/deprecated_attr.go b/ast/deprecated_attr.go new file mode 100644 index 0000000..d86f2cd --- /dev/null +++ b/ast/deprecated_attr.go @@ -0,0 +1,51 @@ +package ast + +// DeprecatedAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type DeprecatedAttr struct { + Addr Address + Pos Position + Message1 string + Message2 string + IsInherited bool + ChildNodes []Node +} + +func parseDeprecatedAttr(line string) *DeprecatedAttr { + groups := groupsFromRegex( + `<(?P.*)>(?P Inherited)? "(?P.*?)"(?P ".*?")?`, + line, + ) + + return &DeprecatedAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Message1: removeQuotes(groups["message1"]), + Message2: removeQuotes(groups["message2"]), + IsInherited: len(groups["inherited"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *DeprecatedAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *DeprecatedAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *DeprecatedAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *DeprecatedAttr) Position() Position { + return n.Pos +} diff --git a/ast/deprecated_attr_test.go b/ast/deprecated_attr_test.go new file mode 100644 index 0000000..c6de681 --- /dev/null +++ b/ast/deprecated_attr_test.go @@ -0,0 +1,36 @@ +package ast + +import ( + "testing" +) + +func TestDeprecatedAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fec4b0ab9c0 "This function is provided for compatibility reasons only. Due to security concerns inherent in the design of tempnam(3), it is highly recommended that you use mkstemp(3) instead." ""`: &DeprecatedAttr{ + Addr: 0x7fec4b0ab9c0, + Pos: NewPositionFromString("line:180:48, col:63"), + Message1: "This function is provided for compatibility reasons only. Due to security concerns inherent in the design of tempnam(3), it is highly recommended that you use mkstemp(3) instead.", + Message2: "", + IsInherited: false, + ChildNodes: []Node{}, + }, + `0xb75d00 "This function or variable may be unsafe. Consider using _snwprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details." ""`: &DeprecatedAttr{ + Addr: 0xb75d00, + Pos: NewPositionFromString("line:1107:12"), + Message1: "This function or variable may be unsafe. Consider using _snwprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.", + Message2: "", + IsInherited: false, + ChildNodes: []Node{}, + }, + `0xb75d00 Inherited "This function or variable may be unsafe. Consider using _snwprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details." ""`: &DeprecatedAttr{ + Addr: 0xb75d00, + Pos: NewPositionFromString("line:1107:12"), + Message1: "This function or variable may be unsafe. Consider using _snwprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.", + Message2: "", + IsInherited: true, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/disable_tail_calls_attr.go b/ast/disable_tail_calls_attr.go new file mode 100644 index 0000000..86007a1 --- /dev/null +++ b/ast/disable_tail_calls_attr.go @@ -0,0 +1,45 @@ +package ast + +// DisableTailCallsAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type DisableTailCallsAttr struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseDisableTailCallsAttr(line string) *DisableTailCallsAttr { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &DisableTailCallsAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *DisableTailCallsAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *DisableTailCallsAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *DisableTailCallsAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *DisableTailCallsAttr) Position() Position { + return n.Pos +} diff --git a/ast/disable_tail_calls_attr_test.go b/ast/disable_tail_calls_attr_test.go new file mode 100644 index 0000000..5168b33 --- /dev/null +++ b/ast/disable_tail_calls_attr_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestDisableTailCallsAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fc8fa094558 `: &DisableTailCallsAttr{ + Addr: 0x7fc8fa094558, + Pos: NewPositionFromString("col:107"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/do_stmt.go b/ast/do_stmt.go new file mode 100644 index 0000000..09e18dd --- /dev/null +++ b/ast/do_stmt.go @@ -0,0 +1,44 @@ +package ast + +// DoStmt is node represent 'do' +type DoStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseDoStmt(line string) *DoStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &DoStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *DoStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *DoStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *DoStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *DoStmt) Position() Position { + return n.Pos +} diff --git a/ast/do_stmt_test.go b/ast/do_stmt_test.go new file mode 100644 index 0000000..fac8350 --- /dev/null +++ b/ast/do_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestDoStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7ff36d0a0938 `: &DoStmt{ + Addr: 0x7ff36d0a0938, + Pos: NewPositionFromString("line:11:5, line:14:23"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/elaborated_type.go b/ast/elaborated_type.go new file mode 100644 index 0000000..b1fe6f9 --- /dev/null +++ b/ast/elaborated_type.go @@ -0,0 +1,46 @@ +package ast + +// ElaboratedType is elaborated type +type ElaboratedType struct { + Addr Address + Type string + Tags string + ChildNodes []Node +} + +func parseElaboratedType(line string) *ElaboratedType { + groups := groupsFromRegex( + "'(?P.*?)' (?P.+)", + line, + ) + + return &ElaboratedType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + Tags: groups["tags"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ElaboratedType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ElaboratedType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ElaboratedType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ElaboratedType) Position() Position { + return Position{} +} diff --git a/ast/elaborated_type_test.go b/ast/elaborated_type_test.go new file mode 100644 index 0000000..ba792a2 --- /dev/null +++ b/ast/elaborated_type_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestElaboratedType(t *testing.T) { + nodes := map[string]Node{ + `0x7f873686c120 'union __mbstate_t' sugar`: &ElaboratedType{ + Addr: 0x7f873686c120, + Type: "union __mbstate_t", + Tags: "sugar", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/empty_decl.go b/ast/empty_decl.go new file mode 100644 index 0000000..84b319f --- /dev/null +++ b/ast/empty_decl.go @@ -0,0 +1,47 @@ +package ast + +// EmptyDecl - element of AST +type EmptyDecl struct { + Addr Address + Pos Position + Position2 Position + ChildNodes []Node +} + +func parseEmptyDecl(line string) *EmptyDecl { + groups := groupsFromRegex( + `<(?P.*)> + ( (?P.*))?`, + line, + ) + + return &EmptyDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: NewPositionFromString(groups["position2"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *EmptyDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *EmptyDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *EmptyDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *EmptyDecl) Position() Position { + return n.Pos +} diff --git a/ast/empty_decl_test.go b/ast/empty_decl_test.go new file mode 100644 index 0000000..2b1d88a --- /dev/null +++ b/ast/empty_decl_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestEmptyDecl(t *testing.T) { + nodes := map[string]Node{ + `0x480bec8 col:13`: &EmptyDecl{ + Addr: 0x480bec8, + Pos: NewPositionFromString("col:13"), + Position2: NewPositionFromString("col:13"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/enum.go b/ast/enum.go new file mode 100644 index 0000000..0d5c965 --- /dev/null +++ b/ast/enum.go @@ -0,0 +1,44 @@ +package ast + +// Enum struct +type Enum struct { + Addr Address + Name string + ChildNodes []Node +} + +func parseEnum(line string) *Enum { + groups := groupsFromRegex( + "'(?P.*?)'", + line, + ) + + return &Enum{ + Addr: ParseAddress(groups["address"]), + Name: groups["name"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *Enum) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *Enum) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *Enum) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *Enum) Position() Position { + return Position{} +} diff --git a/ast/enum_constant_decl.go b/ast/enum_constant_decl.go new file mode 100644 index 0000000..772e7e3 --- /dev/null +++ b/ast/enum_constant_decl.go @@ -0,0 +1,56 @@ +package ast + +// EnumConstantDecl is node represents a enum constant declaration. +type EnumConstantDecl struct { + Addr Address + Pos Position + Position2 string + Referenced bool + Name string + Type string + ChildNodes []Node +} + +func parseEnumConstantDecl(line string) *EnumConstantDecl { + groups := groupsFromRegex( + `<(?P.*)> + ( (?P[^ ]+))? + ( (?Preferenced))? + (?P.+) + '(?P.+?)'`, + line, + ) + + return &EnumConstantDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: groups["position2"], + Referenced: len(groups["referenced"]) > 0, + Name: groups["name"], + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *EnumConstantDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *EnumConstantDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *EnumConstantDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *EnumConstantDecl) Position() Position { + return n.Pos +} diff --git a/ast/enum_constant_decl_test.go b/ast/enum_constant_decl_test.go new file mode 100644 index 0000000..eaf747d --- /dev/null +++ b/ast/enum_constant_decl_test.go @@ -0,0 +1,30 @@ +package ast + +import ( + "testing" +) + +func TestEnumConstantDecl(t *testing.T) { + nodes := map[string]Node{ + `0x1660db0 __codecvt_noconv 'int'`: &EnumConstantDecl{ + Addr: 0x1660db0, + Pos: NewPositionFromString("line:185:3"), + Position2: "", + Referenced: false, + Name: "__codecvt_noconv", + Type: "int", + ChildNodes: []Node{}, + }, + `0x3c77ba8 col:3 referenced _ISalnum 'int'`: &EnumConstantDecl{ + Addr: 0x3c77ba8, + Pos: NewPositionFromString("line:59:3, col:65"), + Position2: "col:3", + Referenced: true, + Name: "_ISalnum", + Type: "int", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/enum_decl.go b/ast/enum_decl.go new file mode 100644 index 0000000..de85098 --- /dev/null +++ b/ast/enum_decl.go @@ -0,0 +1,52 @@ +package ast + +import ( + "strings" +) + +// EnumDecl is node represents a enum declaration. +type EnumDecl struct { + Addr Address + Pos Position + Position2 string + Name string + ChildNodes []Node +} + +func parseEnumDecl(line string) *EnumDecl { + groups := groupsFromRegex( + `(?:prev (?P0x[0-9a-f]+) )?<(?P.*)>(?P .+:\d+)?(?P.*)`, + line, + ) + + return &EnumDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: groups["position2"], + Name: strings.TrimSpace(groups["name"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *EnumDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *EnumDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *EnumDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *EnumDecl) Position() Position { + return n.Pos +} diff --git a/ast/enum_decl_test.go b/ast/enum_decl_test.go new file mode 100644 index 0000000..94296c0 --- /dev/null +++ b/ast/enum_decl_test.go @@ -0,0 +1,26 @@ +package ast + +import ( + "testing" +) + +func TestEnumDecl(t *testing.T) { + nodes := map[string]Node{ + `0x22a6c80 __codecvt_result`: &EnumDecl{ + Addr: 0x22a6c80, + Pos: NewPositionFromString("line:180:1, line:186:1"), + Position2: "", + Name: "__codecvt_result", + ChildNodes: []Node{}, + }, + `0x32fb5a0 col:6 week`: &EnumDecl{ + Addr: 0x32fb5a0, + Pos: NewPositionFromString("enum.c:3:1, col:45"), + Position2: " col:6", + Name: "week", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/enum_test.go b/ast/enum_test.go new file mode 100644 index 0000000..970f63e --- /dev/null +++ b/ast/enum_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestEnum(t *testing.T) { + nodes := map[string]Node{ + `0x7f980b858308 'foo'`: &Enum{ + Addr: 0x7f980b858308, + Name: "foo", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/enum_type.go b/ast/enum_type.go new file mode 100644 index 0000000..e21fb7e --- /dev/null +++ b/ast/enum_type.go @@ -0,0 +1,44 @@ +package ast + +// EnumType is enum type +type EnumType struct { + Addr Address + Name string + ChildNodes []Node +} + +func parseEnumType(line string) *EnumType { + groups := groupsFromRegex( + "'(?P.*?)'", + line, + ) + + return &EnumType{ + Addr: ParseAddress(groups["address"]), + Name: groups["name"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *EnumType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *EnumType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *EnumType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *EnumType) Position() Position { + return Position{} +} diff --git a/ast/enum_type_test.go b/ast/enum_type_test.go new file mode 100644 index 0000000..d3fbe35 --- /dev/null +++ b/ast/enum_type_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestEnumType(t *testing.T) { + nodes := map[string]Node{ + `0x7f980b858309 'foo'`: &EnumType{ + Addr: 0x7f980b858309, + Name: "foo", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/field.go b/ast/field.go new file mode 100644 index 0000000..8630d1f --- /dev/null +++ b/ast/field.go @@ -0,0 +1,46 @@ +package ast + +// Field struct +type Field struct { + Addr Address + String1 string + String2 string + ChildNodes []Node +} + +func parseField(line string) *Field { + groups := groupsFromRegex( + `'(?P.*?)' '(?P.*?)'`, + line, + ) + + return &Field{ + Addr: ParseAddress(groups["address"]), + String1: groups["string1"], + String2: groups["string2"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *Field) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *Field) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *Field) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *Field) Position() Position { + return Position{} +} diff --git a/ast/field_decl.go b/ast/field_decl.go new file mode 100644 index 0000000..0c28334 --- /dev/null +++ b/ast/field_decl.go @@ -0,0 +1,67 @@ +package ast + +import ( + "strings" +) + +// FieldDecl is node represents a field declaration. +type FieldDecl struct { + Addr Address + Pos Position + Position2 string + Name string + Type string + Type2 string + Implicit bool + Referenced bool + ChildNodes []Node +} + +func parseFieldDecl(line string) *FieldDecl { + groups := groupsFromRegex( + `<(?P.*)> + (?P col:\d+| line:\d+:\d+)? + (?P implicit)? + (?P referenced)? + (?P \w+?)? + '(?P.+?)' + (:'(?P.*?)')? + `, + line, + ) + + return &FieldDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: strings.TrimSpace(groups["position2"]), + Name: strings.TrimSpace(groups["name"]), + Type: groups["type"], + Type2: groups["type2"], + Implicit: len(groups["implicit"]) > 0, + Referenced: len(groups["referenced"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *FieldDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *FieldDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *FieldDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *FieldDecl) Position() Position { + return n.Pos +} diff --git a/ast/field_decl_test.go b/ast/field_decl_test.go new file mode 100644 index 0000000..79151e2 --- /dev/null +++ b/ast/field_decl_test.go @@ -0,0 +1,122 @@ +package ast + +import ( + "testing" +) + +func TestFieldDecl(t *testing.T) { + nodes := map[string]Node{ + `0x7fef510c4848 col:6 _ur 'int'`: &FieldDecl{ + Addr: 0x7fef510c4848, + Pos: NewPositionFromString("line:141:2, col:6"), + Position2: "col:6", + Name: "_ur", + Type: "int", + Type2: "", + Implicit: false, + Referenced: false, + ChildNodes: []Node{}, + }, + `0x7fef510c46f8 col:16 _ub 'struct __sbuf':'struct __sbuf'`: &FieldDecl{ + Addr: 0x7fef510c46f8, + Pos: NewPositionFromString("line:139:2, col:16"), + Position2: "col:16", + Name: "_ub", + Type: "struct __sbuf", + Type2: "struct __sbuf", + Implicit: false, + Referenced: false, + ChildNodes: []Node{}, + }, + `0x7fef510c3fe0 col:19 _read 'int (* _Nullable)(void *, char *, int)':'int (*)(void *, char *, int)'`: &FieldDecl{ + Addr: 0x7fef510c3fe0, + Pos: NewPositionFromString("line:134:2, col:19"), + Position2: "col:19", + Name: "_read", + Type: "int (* _Nullable)(void *, char *, int)", + Type2: "int (*)(void *, char *, int)", + Implicit: false, + Referenced: false, + ChildNodes: []Node{}, + }, + `0x7fef51073a60 col:40 __cleanup_stack 'struct __darwin_pthread_handler_rec *'`: &FieldDecl{ + Addr: 0x7fef51073a60, + Pos: NewPositionFromString("line:105:2, col:40"), + Position2: "col:40", + Name: "__cleanup_stack", + Type: "struct __darwin_pthread_handler_rec *", + Type2: "", + Implicit: false, + Referenced: false, + ChildNodes: []Node{}, + }, + `0x7fef510738e8 col:7 __opaque 'char [16]'`: &FieldDecl{ + Addr: 0x7fef510738e8, + Pos: NewPositionFromString("line:100:2, col:43"), + Position2: "col:7", + Name: "__opaque", + Type: "char [16]", + Type2: "", + Implicit: false, + Referenced: false, + ChildNodes: []Node{}, + }, + `0x7fe9f5072268 col:6 referenced _lbfsize 'int'`: &FieldDecl{ + Addr: 0x7fe9f5072268, + Pos: NewPositionFromString("line:129:2, col:6"), + Position2: "col:6", + Name: "_lbfsize", + Type: "int", + Type2: "", + Implicit: false, + Referenced: true, + ChildNodes: []Node{}, + }, + `0x7f9bc9083d00 line:91:5 'unsigned short'`: &FieldDecl{ + Addr: 0x7f9bc9083d00, + Pos: NewPositionFromString("line:91:5, line:97:8"), + Position2: "line:91:5", + Name: "", + Type: "unsigned short", + Type2: "", + Implicit: false, + Referenced: false, + ChildNodes: []Node{}, + }, + `0x30363a0 __val 'int [2]'`: &FieldDecl{ + Addr: 0x30363a0, + Pos: NewPositionFromString("col:18, col:29"), + Position2: "", + Name: "__val", + Type: "int [2]", + Type2: "", + Implicit: false, + Referenced: false, + ChildNodes: []Node{}, + }, + `0x17aeac0 col:9 implicit referenced 'struct vec3d_t::(anonymous at main.c:3:9)'`: &FieldDecl{ + Addr: 0x17aeac0, + Pos: NewPositionFromString("line:3:9"), + Position2: "col:9", + Name: "", + Type: "struct vec3d_t::(anonymous at main.c:3:9)", + Type2: "", + Implicit: true, + Referenced: true, + ChildNodes: []Node{}, + }, + `0x56498bf52160 col:21 type 'enum __pid_type':'enum __pid_type'`: &FieldDecl{ + Addr: 0x56498bf52160, + Pos: NewPositionFromString("line:269:5, col:21"), + Position2: "col:21", + Name: "type", + Type: "enum __pid_type", + Type2: "enum __pid_type", + Implicit: false, + Referenced: false, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/field_test.go b/ast/field_test.go new file mode 100644 index 0000000..04c548b --- /dev/null +++ b/ast/field_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestField(t *testing.T) { + nodes := map[string]Node{ + `0x44159a0 '' 'union sigcontext::(anonymous at /usr/include/x86_64-linux-gnu/bits/sigcontext.h:165:17)'`: &Field{ + Addr: 0x44159a0, + String1: "", + String2: "union sigcontext::(anonymous at /usr/include/x86_64-linux-gnu/bits/sigcontext.h:165:17)", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/floating_literal.go b/ast/floating_literal.go new file mode 100644 index 0000000..85d1187 --- /dev/null +++ b/ast/floating_literal.go @@ -0,0 +1,114 @@ +package ast + +import ( + "errors" + "fmt" + "reflect" + + "github.com/elliotchance/c2go/cc" +) + +// FloatingLiteral is type of float literal +type FloatingLiteral struct { + Addr Address + Pos Position + Type string + Value float64 + ChildNodes []Node +} + +func parseFloatingLiteral(line string) *FloatingLiteral { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*?)' (?P.+)", + line, + ) + + return &FloatingLiteral{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Value: atof(groups["value"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *FloatingLiteral) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *FloatingLiteral) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *FloatingLiteral) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *FloatingLiteral) Position() Position { + return n.Pos +} + +// FloatingLiteralError represents one instance of an error where the exact +// floating point value of a FloatingLiteral could not be determined from the +// original source. See RepairFloatingLiteralsFromSource for a full explanation. +type FloatingLiteralError struct { + Node *FloatingLiteral + Err error +} + +// RepairFloatingLiteralsFromSource finds the exact values of floating literals +// by reading their values directly from the preprocessed source. +// +// The clang AST only serializes floating point values in scientific notation +// with 7 significant digits. This is not enough when dealing with precise +// numbers. +// +// The only solution is to read the original floating literal from the source +// code. We can do this by using the positional information on the node. +// +// If the floating literal cannot be resolved for any reason the original value +// will remain. This function will return all errors encountered. +func RepairFloatingLiteralsFromSource(rootNode Node, preprocessedFile string) []FloatingLiteralError { + errs := []FloatingLiteralError{} + floatingLiteralNodes := + GetAllNodesOfType(rootNode, reflect.TypeOf((*FloatingLiteral)(nil))) + + for _, node := range floatingLiteralNodes { + fNode := node.(*FloatingLiteral) + + // Use the node position to retrieve the original line from the + // preprocessed source. + pos := node.Position() + line, err := + cc.GetLineFromPreprocessedFile(preprocessedFile, pos.File, pos.Line) + + // If there was a problem reading the line we should raise a warning and + // use the value we have. Hopefully that will be an accurate enough + // representation. + if err != nil { + errs = append(errs, FloatingLiteralError{ + Node: fNode, + Err: err, + }) + } + + // Extract the exact value from the line. + if pos.Column-1 >= len(line) { + errs = append(errs, FloatingLiteralError{ + Node: fNode, + Err: errors.New("cannot get exact value exact value"), + }) + } else { + fmt.Sscan(line[pos.Column-1:], &fNode.Value) + } + } + + return errs +} diff --git a/ast/floating_literal_test.go b/ast/floating_literal_test.go new file mode 100644 index 0000000..496aa20 --- /dev/null +++ b/ast/floating_literal_test.go @@ -0,0 +1,26 @@ +package ast + +import ( + "testing" +) + +func TestFloatingLiteral(t *testing.T) { + nodes := map[string]Node{ + `0x7febe106f5e8 'double' 1.230000e+00`: &FloatingLiteral{ + Addr: 0x7febe106f5e8, + Pos: NewPositionFromString("col:24"), + Type: "double", + Value: 1.23, + ChildNodes: []Node{}, + }, + `0x21c65b8 'double' 2.718282e+00`: &FloatingLiteral{ + Addr: 0x21c65b8, + Pos: NewPositionFromString("col:41"), + Type: "double", + Value: 2.718282e+00, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/for_stmt.go b/ast/for_stmt.go new file mode 100644 index 0000000..f5f6ea4 --- /dev/null +++ b/ast/for_stmt.go @@ -0,0 +1,44 @@ +package ast + +// ForStmt is node represent 'for' +type ForStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseForStmt(line string) *ForStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &ForStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ForStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ForStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ForStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ForStmt) Position() Position { + return n.Pos +} diff --git a/ast/for_stmt_test.go b/ast/for_stmt_test.go new file mode 100644 index 0000000..351927b --- /dev/null +++ b/ast/for_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestForStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7f961e018848 `: &ForStmt{ + Addr: 0x7f961e018848, + Pos: NewPositionFromString("line:9:4, line:10:70"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/format_arg_attr.go b/ast/format_arg_attr.go new file mode 100644 index 0000000..fd62282 --- /dev/null +++ b/ast/format_arg_attr.go @@ -0,0 +1,48 @@ +package ast + +// FormatArgAttr is a type of attribute that is optionally attached to a +// function definition. +type FormatArgAttr struct { + Addr Address + Pos Position + Arg string + ChildNodes []Node +} + +func parseFormatArgAttr(line string) *FormatArgAttr { + groups := groupsFromRegex( + `<(?P.*)> + *(?P\d+)`, + line, + ) + + return &FormatArgAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Arg: groups["arg"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *FormatArgAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *FormatArgAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *FormatArgAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *FormatArgAttr) Position() Position { + return n.Pos +} diff --git a/ast/format_arg_attr_test.go b/ast/format_arg_attr_test.go new file mode 100644 index 0000000..3600360 --- /dev/null +++ b/ast/format_arg_attr_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestFormatArgAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7f1234567890 1`: &FormatArgAttr{ + Addr: 0x7f1234567890, + Pos: NewPositionFromString("col:47, col:57"), + Arg: "1", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/format_attr.go b/ast/format_attr.go new file mode 100644 index 0000000..35e336d --- /dev/null +++ b/ast/format_attr.go @@ -0,0 +1,64 @@ +package ast + +import ( + "github.com/elliotchance/c2go/util" +) + +// FormatAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type FormatAttr struct { + Addr Address + Pos Position + Implicit bool + Inherited bool + FunctionName string + Unknown1 int + Unknown2 int + ChildNodes []Node +} + +func parseFormatAttr(line string) *FormatAttr { + groups := groupsFromRegex( + `<(?P.*)> + (?P Implicit)? + (?P Inherited)? + (?P\w+) + (?P\d+) + (?P\d+)`, + line, + ) + + return &FormatAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Implicit: len(groups["implicit"]) > 0, + Inherited: len(groups["inherited"]) > 0, + FunctionName: groups["function"], + Unknown1: util.Atoi(groups["unknown1"]), + Unknown2: util.Atoi(groups["unknown2"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *FormatAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *FormatAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *FormatAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *FormatAttr) Position() Position { + return n.Pos +} diff --git a/ast/format_attr_test.go b/ast/format_attr_test.go new file mode 100644 index 0000000..7fa23c7 --- /dev/null +++ b/ast/format_attr_test.go @@ -0,0 +1,42 @@ +package ast + +import ( + "testing" +) + +func TestFormatAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fcc8d8ecee8 Implicit printf 2 3`: &FormatAttr{ + Addr: 0x7fcc8d8ecee8, + Pos: NewPositionFromString("col:6"), + Implicit: true, + Inherited: false, + FunctionName: "printf", + Unknown1: 2, + Unknown2: 3, + ChildNodes: []Node{}, + }, + `0x7fcc8d8ecff8 printf 2 3`: &FormatAttr{ + Addr: 0x7fcc8d8ecff8, + Pos: NewPositionFromString("/usr/include/sys/cdefs.h:351:18, col:61"), + Implicit: false, + Inherited: false, + FunctionName: "printf", + Unknown1: 2, + Unknown2: 3, + ChildNodes: []Node{}, + }, + `0x273b4d0 Inherited printf 2 3`: &FormatAttr{ + Addr: 0x273b4d0, + Pos: NewPositionFromString("line:357:12"), + Implicit: false, + Inherited: true, + FunctionName: "printf", + Unknown1: 2, + Unknown2: 3, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/full_comment.go b/ast/full_comment.go new file mode 100644 index 0000000..fcbaa8b --- /dev/null +++ b/ast/full_comment.go @@ -0,0 +1,44 @@ +package ast + +// FullComment is a type of comment +type FullComment struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseFullComment(line string) *FullComment { + groups := groupsFromRegex( + `<(?P.*)>`, + line, + ) + + return &FullComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *FullComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *FullComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *FullComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *FullComment) Position() Position { + return n.Pos +} diff --git a/ast/full_comment_test.go b/ast/full_comment_test.go new file mode 100644 index 0000000..1e4f839 --- /dev/null +++ b/ast/full_comment_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestFullComment(t *testing.T) { + nodes := map[string]Node{ + `0x3860920 `: &FullComment{ + Addr: 0x3860920, + Pos: NewPositionFromString("line:10176:4, line:10180:45"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/function_decl.go b/ast/function_decl.go new file mode 100644 index 0000000..c99727f --- /dev/null +++ b/ast/function_decl.go @@ -0,0 +1,85 @@ +package ast + +import ( + "strings" +) + +// FunctionDecl is node represents a function declaration. +type FunctionDecl struct { + Addr Address + Pos Position + Prev string + Parent string + Position2 string + Name string + Type string + Type2 string + IsExtern bool + IsImplicit bool + IsUsed bool + IsReferenced bool + IsStatic bool + IsInline bool + ChildNodes []Node +} + +func parseFunctionDecl(line string) *FunctionDecl { + groups := groupsFromRegex( + `(?:parent (?P0x[0-9a-f]+) )? + (?:prev (?P0x[0-9a-f]+) )? + <(?P.*?)> + (?P [^ ]+| [^ ]+)? + (?P implicit)? + (?P used)? + (?P referenced)? + (?P[_\w]+) + '(?P.*?)' + (:'(?P.*?)')? + (?P extern)? + (?P static)? + (?P inline)? + `, + line, + ) + + return &FunctionDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position1"]), + Parent: groups["parent"], + Prev: groups["prev"], + Position2: strings.TrimSpace(groups["position2"]), + Name: groups["name"], + Type: groups["type"], + Type2: groups["type2"], + IsExtern: len(groups["extern"]) > 0, + IsImplicit: len(groups["implicit"]) > 0, + IsUsed: len(groups["used"]) > 0, + IsReferenced: len(groups["referenced"]) > 0, + IsStatic: len(groups["static"]) > 0, + IsInline: len(groups["inline"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *FunctionDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *FunctionDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *FunctionDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *FunctionDecl) Position() Position { + return n.Pos +} diff --git a/ast/function_decl_test.go b/ast/function_decl_test.go new file mode 100644 index 0000000..3f56a6f --- /dev/null +++ b/ast/function_decl_test.go @@ -0,0 +1,222 @@ +package ast + +import ( + "testing" +) + +func TestFunctionDecl(t *testing.T) { + nodes := map[string]Node{ + `0x7fb5a90e60d0 col:7 clearerr 'void (FILE *)'`: &FunctionDecl{ + Addr: 0x7fb5a90e60d0, + Pos: NewPositionFromString("line:231:1, col:22"), + Prev: "", + Position2: "col:7", + Name: "clearerr", + Type: "void (FILE *)", + Type2: "", + IsExtern: false, + IsImplicit: false, + IsUsed: false, + IsReferenced: false, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x7fb5a90e2a50 /usr/include/sys/stdio.h:39:5 renameat 'int (int, const char *, int, const char *)'`: &FunctionDecl{ + Addr: 0x7fb5a90e2a50, + Pos: NewPositionFromString("/usr/include/sys/stdio.h:39:1, /usr/include/AvailabilityInternal.h:21697:126"), + Prev: "", + Position2: "/usr/include/sys/stdio.h:39:5", + Name: "renameat", + Type: "int (int, const char *, int, const char *)", + Type2: "", + IsExtern: false, + IsImplicit: false, + IsUsed: false, + IsReferenced: false, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x7fb5a90e9b70 col:6 implicit fprintf 'int (FILE *, const char *, ...)' extern`: &FunctionDecl{ + Addr: 0x7fb5a90e9b70, + Pos: NewPositionFromString("/usr/include/stdio.h:244:6"), + Prev: "", + Position2: "col:6", + Name: "fprintf", + Type: "int (FILE *, const char *, ...)", + Type2: "", + IsExtern: true, + IsImplicit: true, + IsUsed: false, + IsReferenced: false, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x7fb5a90e9d40 prev 0x7fb5a90e9b70 /usr/include/stdio.h:244:6 fprintf 'int (FILE *, const char *, ...)'`: &FunctionDecl{ + Addr: 0x7fb5a90e9d40, + Pos: NewPositionFromString("col:1, /usr/include/sys/cdefs.h:351:63"), + Prev: "0x7fb5a90e9b70", + Position2: "/usr/include/stdio.h:244:6", + Name: "fprintf", + Type: "int (FILE *, const char *, ...)", + Type2: "", + IsExtern: false, + IsImplicit: false, + IsUsed: false, + IsReferenced: false, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x7fb5a90ec210 col:6 implicit used printf 'int (const char *, ...)' extern`: &FunctionDecl{ + Addr: 0x7fb5a90ec210, + Pos: NewPositionFromString("line:259:6"), + Prev: "", + Position2: "col:6", + Name: "printf", + Type: "int (const char *, ...)", + Type2: "", + IsExtern: true, + IsImplicit: true, + IsUsed: true, + IsReferenced: false, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x2ae30d8 :17:1 __acos 'double (double)' extern`: &FunctionDecl{ + Addr: 0x2ae30d8, + Pos: NewPositionFromString("/usr/include/math.h:65:3, /usr/include/x86_64-linux-gnu/sys/cdefs.h:57:54"), + Prev: "", + Position2: ":17:1", + Name: "__acos", + Type: "double (double)", + Type2: "", + IsExtern: true, + IsImplicit: false, + IsUsed: false, + IsReferenced: false, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x7fc595071500 line:26:5 referenced main 'int (int, char **)'`: &FunctionDecl{ + Addr: 0x7fc595071500, + Pos: NewPositionFromString("line:26:1, line:69:1"), + Prev: "", + Position2: "line:26:5", + Name: "main", + Type: "int (int, char **)", + Type2: "", + IsExtern: false, + IsImplicit: false, + IsUsed: false, + IsReferenced: true, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x55973a008cb0 line:93619:12 used exprIsConst 'int (Expr *, int, int)' static`: &FunctionDecl{ + Addr: 0x55973a008cb0, + Pos: NewPositionFromString("line:93619:1, line:93630:1"), + Prev: "", + Position2: "line:93619:12", + Name: "exprIsConst", + Type: "int (Expr *, int, int)", + Type2: "", + IsExtern: false, + IsImplicit: false, + IsUsed: true, + IsReferenced: false, + IsStatic: true, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x563ade547cb8 line:14:2 safe_unary_minus_func_int8_t_s 'int8_t (int8_t)':'int8_t (int8_t)' static`: &FunctionDecl{ + Addr: 0x563ade547cb8, + Pos: NewPositionFromString("safe_math.h:13:1, line:25:1"), + Prev: "", + Position2: "line:14:2", + Name: "safe_unary_minus_func_int8_t_s", + Type: "int8_t (int8_t)", + Type2: "int8_t (int8_t)", + IsExtern: false, + IsImplicit: false, + IsUsed: false, + IsReferenced: false, + IsStatic: true, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x556cac571be0 line:9:26 sqlite3Hwtime1 'unsigned long (void)' inline`: &FunctionDecl{ + Addr: 0x556cac571be0, + Pos: NewPositionFromString("tests/asm.c:9:1, line:13:1"), + Prev: "", + Position2: "line:9:26", + Name: "sqlite3Hwtime1", + Type: "unsigned long (void)", + Type2: "", + IsExtern: false, + IsImplicit: false, + IsUsed: false, + IsReferenced: false, + IsStatic: false, + IsInline: true, + ChildNodes: []Node{}, + }, + `0x21c3da0 line:8201:25 used insertvertex 'enum insertvertexresult (struct mesh *, struct behavior *, vertex, struct otri *, struct osub *, int, int)'`: &FunctionDecl{ + Addr: 0x21c3da0, + Pos: NewPositionFromString("line:8201:1, line:8786:1"), + Prev: "", + Position2: "line:8201:25", + Name: "insertvertex", + Type: "enum insertvertexresult (struct mesh *, struct behavior *, vertex, struct otri *, struct osub *, int, int)", + Type2: "", + IsExtern: false, + IsImplicit: false, + IsUsed: true, + IsReferenced: false, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x30bdba8 parent 0x304fbb0 col:30 used getinfo 'enum countries ()'`: &FunctionDecl{ + Addr: 0x30bdba8, + Pos: NewPositionFromString("col:3, col:38"), + Prev: "", + Parent: "0x304fbb0", + Position2: "col:30", + Name: "getinfo", + Type: "enum countries ()", + Type2: "", + IsExtern: false, + IsImplicit: false, + IsUsed: true, + IsReferenced: false, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + `0x353d3b8 parent 0x31e9ba0 prev 0x33b0810 col:22 used dmatrix 'double **(long, long, long, long)'`: &FunctionDecl{ + Addr: 0x353d3b8, + Pos: NewPositionFromString("col:2, col:30"), + Prev: "0x33b0810", + Parent: "0x31e9ba0", + Position2: "col:22", + Name: "dmatrix", + Type: "double **(long, long, long, long)", + Type2: "", + IsExtern: false, + IsImplicit: false, + IsUsed: true, + IsReferenced: false, + IsStatic: false, + IsInline: false, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/function_proto_type.go b/ast/function_proto_type.go new file mode 100644 index 0000000..b84abd7 --- /dev/null +++ b/ast/function_proto_type.go @@ -0,0 +1,46 @@ +package ast + +// FunctionProtoType is function proto type +type FunctionProtoType struct { + Addr Address + Type string + Kind string + ChildNodes []Node +} + +func parseFunctionProtoType(line string) *FunctionProtoType { + groups := groupsFromRegex( + "'(?P.*?)' (?P.*)", + line, + ) + + return &FunctionProtoType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + Kind: groups["kind"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *FunctionProtoType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *FunctionProtoType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *FunctionProtoType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *FunctionProtoType) Position() Position { + return Position{} +} diff --git a/ast/function_proto_type_test.go b/ast/function_proto_type_test.go new file mode 100644 index 0000000..31b4984 --- /dev/null +++ b/ast/function_proto_type_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestFunctionProtoType(t *testing.T) { + nodes := map[string]Node{ + `0x7fa3b88bbb30 'struct _opaque_pthread_t *' foo`: &FunctionProtoType{ + Addr: 0x7fa3b88bbb30, + Type: "struct _opaque_pthread_t *", + Kind: "foo", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/gcc_asm_stmt.go b/ast/gcc_asm_stmt.go new file mode 100644 index 0000000..c5d4a6f --- /dev/null +++ b/ast/gcc_asm_stmt.go @@ -0,0 +1,44 @@ +package ast + +// GCCAsmStmt is node represent gcc assembler +type GCCAsmStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseGCCAsmStmt(line string) *GCCAsmStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &GCCAsmStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *GCCAsmStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *GCCAsmStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *GCCAsmStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *GCCAsmStmt) Position() Position { + return n.Pos +} diff --git a/ast/gcc_asm_stmt_test.go b/ast/gcc_asm_stmt_test.go new file mode 100644 index 0000000..4c42ecd --- /dev/null +++ b/ast/gcc_asm_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestGCCAsmStmtStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fad830c9e38 `: &GCCAsmStmt{ + Addr: 0x7fad830c9e38, + Pos: NewPositionFromString("line:13:5, col:57"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/go_stmt.go b/ast/go_stmt.go new file mode 100644 index 0000000..f96dea2 --- /dev/null +++ b/ast/go_stmt.go @@ -0,0 +1,48 @@ +package ast + +// GotoStmt is node represent 'goto' +type GotoStmt struct { + Addr Address + Pos Position + Name string + Position2 string + ChildNodes []Node +} + +func parseGotoStmt(line string) *GotoStmt { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*)' (?P.*)", + line, + ) + + return &GotoStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Name: groups["name"], + Position2: groups["position2"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *GotoStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *GotoStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *GotoStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *GotoStmt) Position() Position { + return n.Pos +} diff --git a/ast/go_stmt_test.go b/ast/go_stmt_test.go new file mode 100644 index 0000000..0c7cdcc --- /dev/null +++ b/ast/go_stmt_test.go @@ -0,0 +1,19 @@ +package ast + +import ( + "testing" +) + +func TestGotoStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fb9cc1994d8 'end_getDigits' 0x7fb9cc199490`: &GotoStmt{ + Addr: 0x7fb9cc1994d8, + Pos: NewPositionFromString("line:18893:9, col:14"), + Name: "end_getDigits", + Position2: "0x7fb9cc199490", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/html_end_tag_comment.go b/ast/html_end_tag_comment.go new file mode 100644 index 0000000..d29235e --- /dev/null +++ b/ast/html_end_tag_comment.go @@ -0,0 +1,46 @@ +package ast + +// HTMLEndTagComment is a type of comment +type HTMLEndTagComment struct { + Addr Address + Pos Position + Name string + ChildNodes []Node +} + +func parseHTMLEndTagComment(line string) *HTMLEndTagComment { + groups := groupsFromRegex( + `<(?P.*)> Name="(?P.*)"`, + line, + ) + + return &HTMLEndTagComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Name: groups["name"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *HTMLEndTagComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *HTMLEndTagComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *HTMLEndTagComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *HTMLEndTagComment) Position() Position { + return n.Pos +} diff --git a/ast/html_end_tag_comment_test.go b/ast/html_end_tag_comment_test.go new file mode 100644 index 0000000..4b2ff9d --- /dev/null +++ b/ast/html_end_tag_comment_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestHTMLEndTagComment(t *testing.T) { + nodes := map[string]Node{ + `0x4259670 Name="i"`: &HTMLEndTagComment{ + Addr: 0x4259670, + Pos: NewPositionFromString("col:27, col:30"), + Name: "i", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/html_start_tag_comment.go b/ast/html_start_tag_comment.go new file mode 100644 index 0000000..0590e94 --- /dev/null +++ b/ast/html_start_tag_comment.go @@ -0,0 +1,46 @@ +package ast + +// HTMLStartTagComment is a type of comment +type HTMLStartTagComment struct { + Addr Address + Pos Position + Name string + ChildNodes []Node +} + +func parseHTMLStartTagComment(line string) *HTMLStartTagComment { + groups := groupsFromRegex( + `<(?P.*)> Name="(?P.*)"`, + line, + ) + + return &HTMLStartTagComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Name: groups["name"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *HTMLStartTagComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *HTMLStartTagComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *HTMLStartTagComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *HTMLStartTagComment) Position() Position { + return n.Pos +} diff --git a/ast/html_start_tag_comment_test.go b/ast/html_start_tag_comment_test.go new file mode 100644 index 0000000..7822e73 --- /dev/null +++ b/ast/html_start_tag_comment_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestHTMLStartTagComment(t *testing.T) { + nodes := map[string]Node{ + `0x4259670 Name="i"`: &HTMLStartTagComment{ + Addr: 0x4259670, + Pos: NewPositionFromString("col:27, col:30"), + Name: "i", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/if_stmt.go b/ast/if_stmt.go new file mode 100644 index 0000000..38f2120 --- /dev/null +++ b/ast/if_stmt.go @@ -0,0 +1,44 @@ +package ast + +// IfStmt is node represent 'if' +type IfStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseIfStmt(line string) *IfStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &IfStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *IfStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *IfStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *IfStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *IfStmt) Position() Position { + return n.Pos +} diff --git a/ast/if_stmt_test.go b/ast/if_stmt_test.go new file mode 100644 index 0000000..52c1df1 --- /dev/null +++ b/ast/if_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestIfStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fc0a69091d0 `: &IfStmt{ + Addr: 0x7fc0a69091d0, + Pos: NewPositionFromString("line:11:7, line:18:7"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/implicit_cast_expr.go b/ast/implicit_cast_expr.go new file mode 100644 index 0000000..a744d34 --- /dev/null +++ b/ast/implicit_cast_expr.go @@ -0,0 +1,56 @@ +package ast + +// ImplicitCastExpr is expression. +type ImplicitCastExpr struct { + Addr Address + Pos Position + Type string + Type2 string + Kind string + ChildNodes []Node +} + +// ImplicitCastExprArrayToPointerDecay - constant +const ImplicitCastExprArrayToPointerDecay = "ArrayToPointerDecay" + +func parseImplicitCastExpr(line string) *ImplicitCastExpr { + groups := groupsFromRegex( + `<(?P.*)> + '(?P.*?)' + (:'(?P.*?)')? + <(?P.*)>`, + line, + ) + + return &ImplicitCastExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Type2: groups["type2"], + Kind: groups["kind"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ImplicitCastExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ImplicitCastExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ImplicitCastExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ImplicitCastExpr) Position() Position { + return n.Pos +} diff --git a/ast/implicit_cast_expr_test.go b/ast/implicit_cast_expr_test.go new file mode 100644 index 0000000..b19bab0 --- /dev/null +++ b/ast/implicit_cast_expr_test.go @@ -0,0 +1,42 @@ +package ast + +import ( + "testing" +) + +func TestImplicitCastExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7f9f5b0a1288 'FILE *' `: &ImplicitCastExpr{ + Addr: 0x7f9f5b0a1288, + Pos: NewPositionFromString("col:8"), + Type: "FILE *", + Kind: "LValueToRValue", + ChildNodes: []Node{}, + }, + `0x7f9f5b0a7828 'int (*)(int, FILE *)' `: &ImplicitCastExpr{ + Addr: 0x7f9f5b0a7828, + Pos: NewPositionFromString("col:11"), + Type: "int (*)(int, FILE *)", + Kind: "FunctionToPointerDecay", + ChildNodes: []Node{}, + }, + `0x21267c8 'enum week1':'enum week2' `: &ImplicitCastExpr{ + Addr: 0x21267c8, + Pos: NewPositionFromString("col:8"), + Type: "enum week1", + Type2: "enum week2", + Kind: "IntegralCast", + ChildNodes: []Node{}, + }, + `0x26fd2d8 'extCoord':'extCoord' `: &ImplicitCastExpr{ + Addr: 0x26fd2d8, + Pos: NewPositionFromString("col:20, col:32"), + Type: "extCoord", + Type2: "extCoord", + Kind: "LValueToRValue", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/implicit_value_init_expr.go b/ast/implicit_value_init_expr.go new file mode 100644 index 0000000..abe3e7e --- /dev/null +++ b/ast/implicit_value_init_expr.go @@ -0,0 +1,48 @@ +package ast + +// ImplicitValueInitExpr is expression +type ImplicitValueInitExpr struct { + Addr Address + Pos Position + Type1 string + Type2 string + ChildNodes []Node +} + +func parseImplicitValueInitExpr(line string) *ImplicitValueInitExpr { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*?)'(:'(?P.*)')?", + line, + ) + + return &ImplicitValueInitExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type1: groups["type1"], + Type2: groups["type2"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ImplicitValueInitExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ImplicitValueInitExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ImplicitValueInitExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ImplicitValueInitExpr) Position() Position { + return n.Pos +} diff --git a/ast/implicit_value_init_expr_test.go b/ast/implicit_value_init_expr_test.go new file mode 100644 index 0000000..1ae0350 --- /dev/null +++ b/ast/implicit_value_init_expr_test.go @@ -0,0 +1,26 @@ +package ast + +import ( + "testing" +) + +func TestImplicitValueInitExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7f8c3396fbd8 <> 'sqlite3StatValueType':'long long'`: &ImplicitValueInitExpr{ + Addr: 0x7f8c3396fbd8, + Pos: NewPositionFromString(""), + Type1: "sqlite3StatValueType", + Type2: "long long", + ChildNodes: []Node{}, + }, + `0x7feecb0d6af0 <> 'char'`: &ImplicitValueInitExpr{ + Addr: 0x7feecb0d6af0, + Pos: NewPositionFromString(""), + Type1: "char", + Type2: "", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/incomplete_array_type.go b/ast/incomplete_array_type.go new file mode 100644 index 0000000..7cbbb7a --- /dev/null +++ b/ast/incomplete_array_type.go @@ -0,0 +1,44 @@ +package ast + +// IncompleteArrayType is incomplete array type +type IncompleteArrayType struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseIncompleteArrayType(line string) *IncompleteArrayType { + groups := groupsFromRegex( + "'(?P.*)' ", + line, + ) + + return &IncompleteArrayType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *IncompleteArrayType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *IncompleteArrayType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *IncompleteArrayType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *IncompleteArrayType) Position() Position { + return Position{} +} diff --git a/ast/incomplete_array_type_test.go b/ast/incomplete_array_type_test.go new file mode 100644 index 0000000..d3d4c71 --- /dev/null +++ b/ast/incomplete_array_type_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestIncompleteArrayType(t *testing.T) { + nodes := map[string]Node{ + `0x7fcb7d005c20 'int []' `: &IncompleteArrayType{ + Addr: 0x7fcb7d005c20, + Type: "int []", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/indirect_field_decl.go b/ast/indirect_field_decl.go new file mode 100644 index 0000000..5dc03a3 --- /dev/null +++ b/ast/indirect_field_decl.go @@ -0,0 +1,58 @@ +package ast + +import "strings" + +// IndirectFieldDecl is node represents a indirect field declaration. +type IndirectFieldDecl struct { + Addr Address + Pos Position + Position2 string + Implicit bool + Name string + Type string + ChildNodes []Node +} + +func parseIndirectFieldDecl(line string) *IndirectFieldDecl { + groups := groupsFromRegex( + `<(?P.*)> + (?P [^ ]+:[\d:]+)? + (?P implicit)? + (?P\w+) + '(?P.+?)'`, + line, + ) + + return &IndirectFieldDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: strings.TrimSpace(groups["position2"]), + Implicit: len(groups["implicit"]) > 0, + Name: groups["name"], + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *IndirectFieldDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *IndirectFieldDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *IndirectFieldDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *IndirectFieldDecl) Position() Position { + return n.Pos +} diff --git a/ast/indirect_field_decl_test.go b/ast/indirect_field_decl_test.go new file mode 100644 index 0000000..3079270 --- /dev/null +++ b/ast/indirect_field_decl_test.go @@ -0,0 +1,21 @@ +package ast + +import ( + "testing" +) + +func TestIndirectFieldDecl(t *testing.T) { + nodes := map[string]Node{ + `0x2be19a8 col:25 implicit fpstate 'struct _fpstate *'`: &IndirectFieldDecl{ + Addr: 0x2be19a8, + Pos: NewPositionFromString("line:167:25"), + Position2: "col:25", + Implicit: true, + Name: "fpstate", + Type: "struct _fpstate *", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/init_list_expr.go b/ast/init_list_expr.go new file mode 100644 index 0000000..7ad116a --- /dev/null +++ b/ast/init_list_expr.go @@ -0,0 +1,48 @@ +package ast + +// InitListExpr is expression. +type InitListExpr struct { + Addr Address + Pos Position + Type1 string + Type2 string + ChildNodes []Node +} + +func parseInitListExpr(line string) *InitListExpr { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*?)'(:'(?P.*)')?", + line, + ) + + return &InitListExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type1: groups["type1"], + Type2: groups["type2"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *InitListExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *InitListExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *InitListExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *InitListExpr) Position() Position { + return n.Pos +} diff --git a/ast/init_list_expr_test.go b/ast/init_list_expr_test.go new file mode 100644 index 0000000..a05301a --- /dev/null +++ b/ast/init_list_expr_test.go @@ -0,0 +1,31 @@ +package ast + +import ( + "testing" +) + +func TestInitListExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7fbdd1906c20 'const unsigned char [256]'`: &InitListExpr{ + Addr: 0x7fbdd1906c20, + Pos: NewPositionFromString("col:52, line:17160:1"), + Type1: "const unsigned char [256]", + ChildNodes: []Node{}, + }, + `0x32017f0 'struct node [2]'`: &InitListExpr{ + Addr: 0x32017f0, + Pos: NewPositionFromString("col:24, col:41"), + Type1: "struct node [2]", + ChildNodes: []Node{}, + }, + `0x3201840 'struct node':'struct node'`: &InitListExpr{ + Addr: 0x3201840, + Pos: NewPositionFromString("col:25, col:31"), + Type1: "struct node", + Type2: "struct node", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/inline_command_comment.go b/ast/inline_command_comment.go new file mode 100644 index 0000000..6cdd2e0 --- /dev/null +++ b/ast/inline_command_comment.go @@ -0,0 +1,46 @@ +package ast + +// InlineCommandComment is a type of comment +type InlineCommandComment struct { + Addr Address + Pos Position + Other string + ChildNodes []Node +} + +func parseInlineCommandComment(line string) *InlineCommandComment { + groups := groupsFromRegex( + `<(?P.*)> (?P.*)`, + line, + ) + + return &InlineCommandComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Other: groups["other"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *InlineCommandComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *InlineCommandComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *InlineCommandComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *InlineCommandComment) Position() Position { + return n.Pos +} diff --git a/ast/inline_command_comment_test.go b/ast/inline_command_comment_test.go new file mode 100644 index 0000000..948f65b --- /dev/null +++ b/ast/inline_command_comment_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestInlineCommandComment(t *testing.T) { + nodes := map[string]Node{ + `0x22e3510 Name="NOTE" RenderNormal`: &InlineCommandComment{ + Addr: 0x22e3510, + Pos: NewPositionFromString("col:2, col:6"), + Other: "Name=\"NOTE\" RenderNormal", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/integer_literal.go b/ast/integer_literal.go new file mode 100644 index 0000000..0f22abd --- /dev/null +++ b/ast/integer_literal.go @@ -0,0 +1,48 @@ +package ast + +// IntegerLiteral is type of integer literal +type IntegerLiteral struct { + Addr Address + Pos Position + Type string + Value string + ChildNodes []Node +} + +func parseIntegerLiteral(line string) *IntegerLiteral { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*?)' (?P\\d+)", + line, + ) + + return &IntegerLiteral{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Value: groups["value"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *IntegerLiteral) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *IntegerLiteral) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *IntegerLiteral) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *IntegerLiteral) Position() Position { + return n.Pos +} diff --git a/ast/integer_literal_test.go b/ast/integer_literal_test.go new file mode 100644 index 0000000..9506e0e --- /dev/null +++ b/ast/integer_literal_test.go @@ -0,0 +1,19 @@ +package ast + +import ( + "testing" +) + +func TestIntegerLiteral(t *testing.T) { + nodes := map[string]Node{ + `0x7fbe9804bcc8 'int' 1`: &IntegerLiteral{ + Addr: 0x7fbe9804bcc8, + Pos: NewPositionFromString("col:14"), + Type: "int", + Value: "1", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/label_stmt.go b/ast/label_stmt.go new file mode 100644 index 0000000..58fb88f --- /dev/null +++ b/ast/label_stmt.go @@ -0,0 +1,46 @@ +package ast + +// LabelStmt is node represent a label +type LabelStmt struct { + Addr Address + Pos Position + Name string + ChildNodes []Node +} + +func parseLabelStmt(line string) *LabelStmt { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*)'", + line, + ) + + return &LabelStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Name: groups["name"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *LabelStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *LabelStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *LabelStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *LabelStmt) Position() Position { + return n.Pos +} diff --git a/ast/label_stmt_test.go b/ast/label_stmt_test.go new file mode 100644 index 0000000..a35fcb0 --- /dev/null +++ b/ast/label_stmt_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestLabelStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fe3ba82edb8 'end_getDigits'`: &LabelStmt{ + Addr: 0x7fe3ba82edb8, + Pos: NewPositionFromString("line:18906:1, line:18907:22"), + Name: "end_getDigits", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/malloc_attr.go b/ast/malloc_attr.go new file mode 100644 index 0000000..c38cc4f --- /dev/null +++ b/ast/malloc_attr.go @@ -0,0 +1,45 @@ +package ast + +// MallocAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type MallocAttr struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseMallocAttr(line string) *MallocAttr { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &MallocAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *MallocAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *MallocAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *MallocAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *MallocAttr) Position() Position { + return n.Pos +} diff --git a/ast/malloc_attr_test.go b/ast/malloc_attr_test.go new file mode 100644 index 0000000..dd040c1 --- /dev/null +++ b/ast/malloc_attr_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestMallocAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fc0a69091d1 `: &MallocAttr{ + Addr: 0x7fc0a69091d1, + Pos: NewPositionFromString("line:11:7, line:18:7"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/max_field_alignment_attr.go b/ast/max_field_alignment_attr.go new file mode 100644 index 0000000..992e69a --- /dev/null +++ b/ast/max_field_alignment_attr.go @@ -0,0 +1,49 @@ +package ast + +import "github.com/elliotchance/c2go/util" + +// MaxFieldAlignmentAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type MaxFieldAlignmentAttr struct { + Addr Address + Pos Position + Size int + ChildNodes []Node +} + +func parseMaxFieldAlignmentAttr(line string) *MaxFieldAlignmentAttr { + groups := groupsFromRegex( + `<(?P.*)> Implicit (?P\d*)`, + line, + ) + + return &MaxFieldAlignmentAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Size: util.Atoi(groups["size"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *MaxFieldAlignmentAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *MaxFieldAlignmentAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *MaxFieldAlignmentAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *MaxFieldAlignmentAttr) Position() Position { + return n.Pos +} diff --git a/ast/max_field_alignment_attr_test.go b/ast/max_field_alignment_attr_test.go new file mode 100644 index 0000000..41069b8 --- /dev/null +++ b/ast/max_field_alignment_attr_test.go @@ -0,0 +1,24 @@ +package ast + +import ( + "testing" +) + +func TestMaxFieldAlignmentAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fd4b7063ac0 <> Implicit 32`: &MaxFieldAlignmentAttr{ + Addr: 0x7fd4b7063ac0, + Pos: NewPositionFromString(""), + Size: 32, + ChildNodes: []Node{}, + }, + `0x7fd4b7063ac0 <> Implicit 8`: &MaxFieldAlignmentAttr{ + Addr: 0x7fd4b7063ac0, + Pos: NewPositionFromString(""), + Size: 8, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/member_expr.go b/ast/member_expr.go new file mode 100644 index 0000000..34506d1 --- /dev/null +++ b/ast/member_expr.go @@ -0,0 +1,93 @@ +package ast + +// MemberExpr is expression. +type MemberExpr struct { + Addr Address + Pos Position + Type string + Type2 string + Name string + IsLvalue bool + IsBitfield bool + Address2 string + IsPointer bool + ChildNodes []Node +} + +func parseMemberExpr(line string) *MemberExpr { + groups := groupsFromRegex( + `<(?P.*)> + '(?P.*?)' + (?P:'.*?')? + (?P lvalue)? + (?P bitfield)? + (?P[->.]+) + (?P\w+)? + (?P[0-9a-fx]+)`, + line, + ) + + type2 := groups["type2"] + if type2 != "" { + type2 = type2[2 : len(type2)-1] + } + + return &MemberExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Type2: type2, + IsPointer: groups["pointer"] == "->", + Name: groups["name"], + IsLvalue: len(groups["lvalue"]) > 0, + IsBitfield: len(groups["bitfield"]) > 0, + Address2: groups["address2"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *MemberExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// GetDeclRefExpr gets DeclRefExpr from MemberExpr, or nil if there is no +// DeclRefExpr +func (n *MemberExpr) GetDeclRefExpr() *DeclRefExpr { + for _, child := range n.ChildNodes { + res, ok := child.(*DeclRefExpr) + if ok { + return res + } + + cast, ok := child.(*ImplicitCastExpr) + if ok { + res, ok = cast.ChildNodes[0].(*DeclRefExpr) + if ok { + return res + } + + } + } + + // There is no DeclRefExpr + return nil +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *MemberExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *MemberExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *MemberExpr) Position() Position { + return n.Pos +} diff --git a/ast/member_expr_test.go b/ast/member_expr_test.go new file mode 100644 index 0000000..fb6dad9 --- /dev/null +++ b/ast/member_expr_test.go @@ -0,0 +1,96 @@ +package ast + +import ( + "testing" +) + +func TestMemberExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7fcc758e34a0 'int' lvalue ->_w 0x7fcc758d60c8`: &MemberExpr{ + Addr: 0x7fcc758e34a0, + Pos: NewPositionFromString("col:8, col:12"), + Type: "int", + Type2: "", + IsLvalue: true, + IsBitfield: false, + Name: "_w", + Address2: "0x7fcc758d60c8", + IsPointer: true, + ChildNodes: []Node{}, + }, + `0x7fcc76004210 'unsigned char *' lvalue ->_p 0x7fcc758d6018`: &MemberExpr{ + Addr: 0x7fcc76004210, + Pos: NewPositionFromString("col:12, col:16"), + Type: "unsigned char *", + Type2: "", + IsLvalue: true, + IsBitfield: false, + Name: "_p", + Address2: "0x7fcc758d6018", + IsPointer: true, + ChildNodes: []Node{}, + }, + `0x7f85338325b0 'float' lvalue .constant 0x7f8533832260`: &MemberExpr{ + Addr: 0x7f85338325b0, + Pos: NewPositionFromString("col:4, col:13"), + Type: "float", + Type2: "", + IsLvalue: true, + IsBitfield: false, + Name: "constant", + Address2: "0x7f8533832260", + IsPointer: false, + ChildNodes: []Node{}, + }, + `0x7f8533832670 'char *' lvalue .pointer 0x7f85338322b8`: &MemberExpr{ + Addr: 0x7f8533832670, + Pos: NewPositionFromString("col:4, col:13"), + Type: "char *", + Type2: "", + IsLvalue: true, + IsBitfield: false, + Name: "pointer", + Address2: "0x7f85338322b8", + IsPointer: false, + ChildNodes: []Node{}, + }, + `0x7fb7d5a49ac8 'bft':'unsigned int' lvalue bitfield ->isPrepareV2 0x7fb7d5967f40`: &MemberExpr{ + Addr: 0x7fb7d5a49ac8, + Pos: NewPositionFromString("col:3, col:6"), + Type: "bft", + Type2: "unsigned int", + IsLvalue: true, + IsBitfield: true, + Name: "isPrepareV2", + Address2: "0x7fb7d5967f40", + IsPointer: true, + ChildNodes: []Node{}, + }, + `0x2914fb8 'union vec3d_t::(anonymous at main.c:2:5)' lvalue . 0x2914920`: &MemberExpr{ + Addr: 0x2914fb8, + Pos: NewPositionFromString("col:12, col:14"), + Type: "union vec3d_t::(anonymous at main.c:2:5)", + Type2: "", + IsLvalue: true, + IsBitfield: false, + Name: "", + Address2: "0x2914920", + IsPointer: false, + ChildNodes: []Node{}, + }, + `0x3180ef0 'int' .n 0x317f450`: &MemberExpr{ + Addr: 0x3180ef0, + Pos: NewPositionFromString("col:32, col:48"), + Type: "int", + Type2: "", + IsLvalue: false, + IsBitfield: false, + Name: "n", + Address2: "0x317f450", + IsPointer: false, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/mode_attr.go b/ast/mode_attr.go new file mode 100644 index 0000000..d41469d --- /dev/null +++ b/ast/mode_attr.go @@ -0,0 +1,47 @@ +package ast + +// ModeAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type ModeAttr struct { + Addr Address + Pos Position + Name string + ChildNodes []Node +} + +func parseModeAttr(line string) *ModeAttr { + groups := groupsFromRegex( + "<(?P.*)> (?P.+)", + line, + ) + + return &ModeAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Name: groups["name"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ModeAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ModeAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ModeAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ModeAttr) Position() Position { + return n.Pos +} diff --git a/ast/mode_attr_test.go b/ast/mode_attr_test.go new file mode 100644 index 0000000..df87dd5 --- /dev/null +++ b/ast/mode_attr_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func Test(t *testing.T) { + nodes := map[string]Node{ + `0x7f980b858309 foo`: &ModeAttr{ + Addr: 0x7f980b858309, + Pos: NewPositionFromString("line:11:7, line:18:7"), + Name: "foo", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/no_inline_attr.go b/ast/no_inline_attr.go new file mode 100644 index 0000000..936dc55 --- /dev/null +++ b/ast/no_inline_attr.go @@ -0,0 +1,45 @@ +package ast + +// NoInlineAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type NoInlineAttr struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseNoInlineAttr(line string) *NoInlineAttr { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &NoInlineAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *NoInlineAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *NoInlineAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *NoInlineAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *NoInlineAttr) Position() Position { + return n.Pos +} diff --git a/ast/no_inline_attr_test.go b/ast/no_inline_attr_test.go new file mode 100644 index 0000000..308f705 --- /dev/null +++ b/ast/no_inline_attr_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestNoInlineAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fc02a8a6730 `: &NoInlineAttr{ + Addr: 0x7fc02a8a6730, + Pos: NewPositionFromString("line:24619:23"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/no_throw_attr.go b/ast/no_throw_attr.go new file mode 100644 index 0000000..6222c0d --- /dev/null +++ b/ast/no_throw_attr.go @@ -0,0 +1,52 @@ +package ast + +// NoThrowAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type NoThrowAttr struct { + Addr Address + Pos Position + ChildNodes []Node + Implicit bool + Inherited bool +} + +func parseNoThrowAttr(line string) *NoThrowAttr { + groups := groupsFromRegex( + `<(?P.*)> + (?P Inherited)? + (?P Implicit)? + `, + line, + ) + + return &NoThrowAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + Inherited: len(groups["inherited"]) > 0, + Implicit: len(groups["implicit"]) > 0, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *NoThrowAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *NoThrowAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *NoThrowAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *NoThrowAttr) Position() Position { + return n.Pos +} diff --git a/ast/no_throw_attr_test.go b/ast/no_throw_attr_test.go new file mode 100644 index 0000000..fcc4749 --- /dev/null +++ b/ast/no_throw_attr_test.go @@ -0,0 +1,40 @@ +package ast + +import ( + "testing" +) + +func TestNoThrowAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fa1488273a0 `: &NoThrowAttr{ + Addr: 0x7fa1488273a0, + Pos: NewPositionFromString("line:7:4, line:11:4"), + ChildNodes: []Node{}, + Inherited: false, + Implicit: false, + }, + `0x5605ceaf4b88 Implicit`: &NoThrowAttr{ + Addr: 0x5605ceaf4b88, + Pos: NewPositionFromString("col:12"), + ChildNodes: []Node{}, + Inherited: false, + Implicit: true, + }, + `0x4153c50 Inherited`: &NoThrowAttr{ + Addr: 0x4153c50, + Pos: NewPositionFromString("/usr/include/unistd.h:779:46"), + ChildNodes: []Node{}, + Inherited: true, + Implicit: false, + }, + `0x1038b8828 Inherited Implicit`: &NoThrowAttr{ + Addr: 0x1038b8828, + Pos: NewPositionFromString("col:20"), + ChildNodes: []Node{}, + Inherited: true, + Implicit: true, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/non_null_attr.go b/ast/non_null_attr.go new file mode 100644 index 0000000..98c0631 --- /dev/null +++ b/ast/non_null_attr.go @@ -0,0 +1,83 @@ +package ast + +import ( + "strings" + + "github.com/elliotchance/c2go/util" +) + +// NonNullAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type NonNullAttr struct { + Addr Address + Pos Position + Inherited bool + A int + B int + C int + D int + ChildNodes []Node +} + +func parseNonNullAttr(line string) *NonNullAttr { + groups := groupsFromRegex( + `<(?P.*)> + (?P Inherited)? + (?P \d+)?(?P \d+)?(?P \d+)?(?P \d+)?`, + line, + ) + + a := 0 + if groups["a"] != "" { + a = util.Atoi(strings.TrimSpace(groups["a"])) + } + + b := 0 + if groups["b"] != "" { + b = util.Atoi(strings.TrimSpace(groups["b"])) + } + + c := 0 + if groups["c"] != "" { + c = util.Atoi(strings.TrimSpace(groups["c"])) + } + + d := 0 + if groups["d"] != "" { + d = util.Atoi(strings.TrimSpace(groups["d"])) + } + + return &NonNullAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Inherited: len(groups["inherited"]) > 0, + A: a, + B: b, + C: c, + D: d, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *NonNullAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *NonNullAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *NonNullAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *NonNullAttr) Position() Position { + return n.Pos +} diff --git a/ast/non_null_attr_test.go b/ast/non_null_attr_test.go new file mode 100644 index 0000000..ab47193 --- /dev/null +++ b/ast/non_null_attr_test.go @@ -0,0 +1,82 @@ +package ast + +import ( + "testing" +) + +func TestNonNullAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fa1488273b0 1`: &NonNullAttr{ + Addr: 0x7fa1488273b0, + Pos: NewPositionFromString("line:7:4, line:11:4"), + Inherited: false, + A: 1, + B: 0, + C: 0, + D: 0, + ChildNodes: []Node{}, + }, + `0x2cce280 1`: &NonNullAttr{ + Addr: 0x2cce280, + Pos: NewPositionFromString("/sys/cdefs.h:286:44, /bits/mathcalls.h:115:69"), + Inherited: false, + A: 1, + B: 0, + C: 0, + D: 0, + ChildNodes: []Node{}, + }, + `0x201ede0 0`: &NonNullAttr{ + Addr: 0x201ede0, + Pos: NewPositionFromString("line:145:79, col:93"), + Inherited: false, + A: 0, + B: 0, + C: 0, + D: 0, + ChildNodes: []Node{}, + }, + `0x1b89b20 2 3`: &NonNullAttr{ + Addr: 0x1b89b20, + Pos: NewPositionFromString("col:76, col:93"), + Inherited: false, + A: 2, + B: 3, + C: 0, + D: 0, + ChildNodes: []Node{}, + }, + `0x55f0219e20d0 0 1 4`: &NonNullAttr{ + Addr: 0x55f0219e20d0, + Pos: NewPositionFromString("line:717:22, col:42"), + Inherited: false, + A: 0, + B: 1, + C: 4, + D: 0, + ChildNodes: []Node{}, + }, + `0x248ea60 0 1 2 4`: &NonNullAttr{ + Addr: 0x248ea60, + Pos: NewPositionFromString("line:155:26, col:49"), + Inherited: false, + A: 0, + B: 1, + C: 2, + D: 4, + ChildNodes: []Node{}, + }, + `0x39cf2b0 Inherited 0 1`: &NonNullAttr{ + Addr: 0x39cf2b0, + Pos: NewPositionFromString("col:53"), + Inherited: true, + A: 0, + B: 1, + C: 0, + D: 0, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/not_tail_called_attr.go b/ast/not_tail_called_attr.go new file mode 100644 index 0000000..1829c32 --- /dev/null +++ b/ast/not_tail_called_attr.go @@ -0,0 +1,45 @@ +package ast + +// NotTailCalledAttr is a type of attribute that is optionally attached to function +// declaration. +type NotTailCalledAttr struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseNotTailCalledAttr(line string) *NotTailCalledAttr { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &NotTailCalledAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *NotTailCalledAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *NotTailCalledAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *NotTailCalledAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *NotTailCalledAttr) Position() Position { + return n.Pos +} diff --git a/ast/not_tail_called_attr_test.go b/ast/not_tail_called_attr_test.go new file mode 100644 index 0000000..bf7c9f8 --- /dev/null +++ b/ast/not_tail_called_attr_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestNotTailCalledAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fc8fa094558 `: &NotTailCalledAttr{ + Addr: 0x7fc8fa094558, + Pos: NewPositionFromString("col:107"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/objc_interface.go b/ast/objc_interface.go new file mode 100644 index 0000000..7463f8f --- /dev/null +++ b/ast/objc_interface.go @@ -0,0 +1,44 @@ +package ast + +// ObjCInterface is an Objective-C interface +type ObjCInterface struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseObjCInterface(line string) *ObjCInterface { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &ObjCInterface{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ObjCInterface) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ObjCInterface) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ObjCInterface) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ObjCInterface) Position() Position { + return Position{} +} diff --git a/ast/objc_interface_decl.go b/ast/objc_interface_decl.go new file mode 100644 index 0000000..82fb6f8 --- /dev/null +++ b/ast/objc_interface_decl.go @@ -0,0 +1,66 @@ +package ast + +import ( +// "fmt" + "strings" +) + +// ObjCInterfaceDecl is node represents a typedef declaration. +type ObjCInterfaceDecl struct { + Addr Address + Pos Position + Position2 string + Name string + Implicit bool + ChildNodes []Node +} + +func parseObjCInterfaceDecl(line string) *ObjCInterfaceDecl { + groups := groupsFromRegex( + `(?:prev (?P0x[0-9a-f]+) )? + <(?P|.*)> + (?P | col:\d+| line:\d+:\d+) + (?P implicit)? + (?P \w+)?`, + line, + ) + + /*fmt.Println(line) + fmt.Println("prev = ",groups["prev"]) + fmt.Println("position = ",groups["position"]) + fmt.Println("position2 = ",groups["position2"]) + fmt.Println("implicit = ",len(groups["implicit"])>0) + fmt.Println("name = ",groups["name"])*/ + + return &ObjCInterfaceDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: strings.TrimSpace(groups["position2"]), + Name: strings.TrimSpace(groups["name"]), + Implicit: len(groups["implicit"])>0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ObjCInterfaceDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ObjCInterfaceDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ObjCInterfaceDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ObjCInterfaceDecl) Position() Position { + return n.Pos +} diff --git a/ast/objc_interface_type.go b/ast/objc_interface_type.go new file mode 100644 index 0000000..669406a --- /dev/null +++ b/ast/objc_interface_type.go @@ -0,0 +1,44 @@ +package ast + +// ObjCInterfaceType is an Objective-C interface type +type ObjCInterfaceType struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseObjCInterfaceType(line string) *ObjCInterfaceType { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &ObjCInterfaceType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ObjCInterfaceType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ObjCInterfaceType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ObjCInterfaceType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ObjCInterfaceType) Position() Position { + return Position{} +} diff --git a/ast/objc_method.go b/ast/objc_method.go new file mode 100644 index 0000000..293b434 --- /dev/null +++ b/ast/objc_method.go @@ -0,0 +1,44 @@ +package ast + +// ObjCMethod is an Objective-C method +type ObjCMethod struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseObjCMethod(line string) *ObjCMethod { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &ObjCMethod{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ObjCMethod) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ObjCMethod) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ObjCMethod) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ObjCMethod) Position() Position { + return Position{} +} diff --git a/ast/objc_method_decl.go b/ast/objc_method_decl.go new file mode 100644 index 0000000..f9b05fa --- /dev/null +++ b/ast/objc_method_decl.go @@ -0,0 +1,70 @@ +package ast + +import ( + "strings" +) + +// ObjCMethodDecl is node represents an Objective-C method declaration +type ObjCMethodDecl struct { + Addr Address + Pos Position + Position2 string + Implicit bool + ClassMethod bool + Name string + Type string + Attr string + ChildNodes []Node +} + +func parseObjCMethodDecl(line string) *ObjCMethodDecl { + groups := groupsFromRegex( + `(?:prev (?P0x[0-9a-f]+) )? + <(?P.*.*?|.*.*?|.*|.*?)> + (?P | col:\d+| line:\d+:\d+)? + (?P implicit)? + (?P \+| \-) + (?P.*?) + (?P'.*') + (?P .*)?`, + line, + ) +/* + (?P | col:\d+| line:\d+:\d+)? +*/ + + return &ObjCMethodDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: strings.TrimSpace(groups["position2"]), + Implicit: len(groups["implicit"])>0, + ClassMethod: groups["methodtype"] == " +", + Name: groups["names"], + Type: groups["type"], + Attr: groups["attr"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ObjCMethodDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ObjCMethodDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ObjCMethodDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ObjCMethodDecl) Position() Position { + return n.Pos +} diff --git a/ast/objc_object_pointer_type.go b/ast/objc_object_pointer_type.go new file mode 100644 index 0000000..0607928 --- /dev/null +++ b/ast/objc_object_pointer_type.go @@ -0,0 +1,44 @@ +package ast + +// ObjCObjectPointerType is an Objective-C Object Pointer type +type ObjCObjectPointerType struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseObjCObjectPointerType(line string) *ObjCObjectPointerType { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &ObjCObjectPointerType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ObjCObjectPointerType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ObjCObjectPointerType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ObjCObjectPointerType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ObjCObjectPointerType) Position() Position { + return Position{} +} diff --git a/ast/objc_object_type.go b/ast/objc_object_type.go new file mode 100644 index 0000000..3ec9c83 --- /dev/null +++ b/ast/objc_object_type.go @@ -0,0 +1,44 @@ +package ast + +// ObjCObjectType is an Objective-C Object type +type ObjCObjectType struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseObjCObjectType(line string) *ObjCObjectType { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &ObjCObjectType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ObjCObjectType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ObjCObjectType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ObjCObjectType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ObjCObjectType) Position() Position { + return Position{} +} diff --git a/ast/objc_protocol.go b/ast/objc_protocol.go new file mode 100644 index 0000000..975ce74 --- /dev/null +++ b/ast/objc_protocol.go @@ -0,0 +1,44 @@ +package ast + +// ObjCProtocol is an Objective-C protocol +type ObjCProtocol struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseObjCProtocol(line string) *ObjCProtocol { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &ObjCProtocol{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ObjCProtocol) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ObjCProtocol) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ObjCProtocol) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ObjCProtocol) Position() Position { + return Position{} +} diff --git a/ast/offset_of_expr.go b/ast/offset_of_expr.go new file mode 100644 index 0000000..a149369 --- /dev/null +++ b/ast/offset_of_expr.go @@ -0,0 +1,46 @@ +package ast + +// OffsetOfExpr is expression. +type OffsetOfExpr struct { + Addr Address + Pos Position + Type string + ChildNodes []Node +} + +func parseOffsetOfExpr(line string) *OffsetOfExpr { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*)'", + line, + ) + + return &OffsetOfExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *OffsetOfExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *OffsetOfExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *OffsetOfExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *OffsetOfExpr) Position() Position { + return n.Pos +} diff --git a/ast/offset_of_expr_test.go b/ast/offset_of_expr_test.go new file mode 100644 index 0000000..222a59e --- /dev/null +++ b/ast/offset_of_expr_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestOffsetOfExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7fa855aab838 'unsigned long'`: &OffsetOfExpr{ + Addr: 0x7fa855aab838, + Pos: NewPositionFromString("col:63, col:95"), + Type: "unsigned long", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/packed_attr.go b/ast/packed_attr.go new file mode 100644 index 0000000..d9d8481 --- /dev/null +++ b/ast/packed_attr.go @@ -0,0 +1,45 @@ +package ast + +// PackedAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type PackedAttr struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parsePackedAttr(line string) *PackedAttr { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &PackedAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *PackedAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *PackedAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *PackedAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *PackedAttr) Position() Position { + return n.Pos +} diff --git a/ast/packed_attr_test.go b/ast/packed_attr_test.go new file mode 100644 index 0000000..5975523 --- /dev/null +++ b/ast/packed_attr_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestPackedAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fae33b1ed40 `: &PackedAttr{ + Addr: 0x7fae33b1ed40, + Pos: NewPositionFromString("line:551:18"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/paragraph_comment.go b/ast/paragraph_comment.go new file mode 100644 index 0000000..4fe5c82 --- /dev/null +++ b/ast/paragraph_comment.go @@ -0,0 +1,44 @@ +package ast + +// ParagraphComment is a type of comment +type ParagraphComment struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseParagraphComment(line string) *ParagraphComment { + groups := groupsFromRegex( + `<(?P.*)>`, + line, + ) + + return &ParagraphComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ParagraphComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ParagraphComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ParagraphComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ParagraphComment) Position() Position { + return n.Pos +} diff --git a/ast/paragraph_comment_test.go b/ast/paragraph_comment_test.go new file mode 100644 index 0000000..0b6f5ac --- /dev/null +++ b/ast/paragraph_comment_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestParagraphComment(t *testing.T) { + nodes := map[string]Node{ + `0x3860920 `: &ParagraphComment{ + Addr: 0x3860920, + Pos: NewPositionFromString("line:10176:4, line:10180:45"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/param_command_comment.go b/ast/param_command_comment.go new file mode 100644 index 0000000..8c2e019 --- /dev/null +++ b/ast/param_command_comment.go @@ -0,0 +1,46 @@ +package ast + +// ParamCommandComment is a type of comment +type ParamCommandComment struct { + Addr Address + Pos Position + Other string + ChildNodes []Node +} + +func parseParamCommandComment(line string) *ParamCommandComment { + groups := groupsFromRegex( + `<(?P.*)> (?P.*)`, + line, + ) + + return &ParamCommandComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Other: groups["other"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ParamCommandComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ParamCommandComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ParamCommandComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ParamCommandComment) Position() Position { + return n.Pos +} diff --git a/ast/param_command_comment_test.go b/ast/param_command_comment_test.go new file mode 100644 index 0000000..4b09122 --- /dev/null +++ b/ast/param_command_comment_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestParamCommandComment(t *testing.T) { + nodes := map[string]Node{ + `0x104bca8d0 [in] implicitly Param="__attr" ParamIndex=0`: &ParamCommandComment{ + Addr: 0x104bca8d0, + Pos: NewPositionFromString("col:4, line:59:45"), + Other: "[in] implicitly Param=\"__attr\" ParamIndex=0", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/paren_expr.go b/ast/paren_expr.go new file mode 100644 index 0000000..ad46530 --- /dev/null +++ b/ast/paren_expr.go @@ -0,0 +1,55 @@ +package ast + +// ParenExpr is expression. +type ParenExpr struct { + Addr Address + Pos Position + Type string + Type2 string + Lvalue bool + IsBitfield bool + ChildNodes []Node +} + +func parseParenExpr(line string) *ParenExpr { + groups := groupsFromRegex( + `<(?P.*)> '(?P.*?)'(:'(?P.*)')? + (?P lvalue)? + (?P bitfield)? + `, + line, + ) + + return &ParenExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type1"], + Type2: groups["type2"], + Lvalue: len(groups["lvalue"]) > 0, + IsBitfield: len(groups["bitfield"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ParenExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ParenExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ParenExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ParenExpr) Position() Position { + return n.Pos +} diff --git a/ast/paren_expr_test.go b/ast/paren_expr_test.go new file mode 100644 index 0000000..cb135c2 --- /dev/null +++ b/ast/paren_expr_test.go @@ -0,0 +1,39 @@ +package ast + +import ( + "testing" +) + +func TestParenExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7fb0bc8b2308 'unsigned char'`: &ParenExpr{ + Addr: 0x7fb0bc8b2308, + Pos: NewPositionFromString("col:10, col:25"), + Type: "unsigned char", + Type2: "", + Lvalue: false, + IsBitfield: false, + ChildNodes: []Node{}, + }, + `0x1ff8708 'T_ENUM':'T_ENUM' lvalue`: &ParenExpr{ + Addr: 0x1ff8708, + Pos: NewPositionFromString("col:14, col:17"), + Type: "T_ENUM", + Type2: "T_ENUM", + Lvalue: true, + IsBitfield: false, + ChildNodes: []Node{}, + }, + `0x55efc60798b0 'bft':'unsigned int' lvalue bitfield`: &ParenExpr{ + Addr: 0x55efc60798b0, + Pos: NewPositionFromString("col:15, col:27"), + Type: "bft", + Type2: "unsigned int", + Lvalue: true, + IsBitfield: true, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/paren_type.go b/ast/paren_type.go new file mode 100644 index 0000000..4492935 --- /dev/null +++ b/ast/paren_type.go @@ -0,0 +1,43 @@ +package ast + +// ParenType is paren type +type ParenType struct { + Addr Address + Type string + Sugar bool + ChildNodes []Node +} + +func parseParenType(line string) *ParenType { + groups := groupsFromRegex(`'(?P.*?)' sugar`, line) + + return &ParenType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + Sugar: true, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ParenType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ParenType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ParenType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ParenType) Position() Position { + return Position{} +} diff --git a/ast/paren_type_test.go b/ast/paren_type_test.go new file mode 100644 index 0000000..8513974 --- /dev/null +++ b/ast/paren_type_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestParenType(t *testing.T) { + nodes := map[string]Node{ + `0x7faf820a4c60 'void (int)' sugar`: &ParenType{ + Addr: 0x7faf820a4c60, + Type: "void (int)", + Sugar: true, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/parm_var_decl.go b/ast/parm_var_decl.go new file mode 100644 index 0000000..8fe8a6b --- /dev/null +++ b/ast/parm_var_decl.go @@ -0,0 +1,80 @@ +package ast + +import ( + "strings" +) + +// ParmVarDecl is node represents a parameter of variable declaration. +type ParmVarDecl struct { + Addr Address + Pos Position + Position2 string + Name string + Type string + Type2 string + IsUsed bool + IsReferenced bool + IsRegister bool + ChildNodes []Node +} + +func parseParmVarDecl(line string) *ParmVarDecl { + groups := groupsFromRegex( + `<(?P.*)> + (?P [^ ]+:[\d:]+)? + (?P used)? + (?P referenced)? + (?P \w+)? + '(?P.*?)' + (?P:'.*?')? + (?P register)? + `, + line, + ) + + type2 := groups["type2"] + if type2 != "" { + type2 = type2[2 : len(type2)-1] + } + + if strings.Index(groups["position"], "") > -1 { + groups["position"] = "" + groups["position2"] = "" + } + + return &ParmVarDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: strings.TrimSpace(groups["position2"]), + Name: strings.TrimSpace(groups["name"]), + Type: groups["type"], + Type2: type2, + IsUsed: len(groups["used"]) > 0, + IsReferenced: len(groups["referenced"]) > 0, + IsRegister: len(groups["register"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ParmVarDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ParmVarDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ParmVarDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ParmVarDecl) Position() Position { + return n.Pos +} diff --git a/ast/parm_var_decl_test.go b/ast/parm_var_decl_test.go new file mode 100644 index 0000000..d2a71c1 --- /dev/null +++ b/ast/parm_var_decl_test.go @@ -0,0 +1,119 @@ +package ast + +import ( + "testing" +) + +func TestParmVarDecl(t *testing.T) { + nodes := map[string]Node{ + `0x7f973380f000 col:17 'int'`: &ParmVarDecl{ + Addr: 0x7f973380f000, + Pos: NewPositionFromString("col:14"), + Position2: "col:17", + Type: "int", + Name: "", + Type2: "", + IsUsed: false, + IsReferenced: false, + IsRegister: false, + ChildNodes: []Node{}, + }, + `0x7f973380f070 col:31 'const char *'`: &ParmVarDecl{ + Addr: 0x7f973380f070, + Pos: NewPositionFromString("col:19, col:30"), + Position2: "col:31", + Type: "const char *", + Name: "", + Type2: "", + IsUsed: false, + IsReferenced: false, + ChildNodes: []Node{}, + }, + `0x7f9733816e50 col:37 __filename 'const char *__restrict'`: &ParmVarDecl{ + Addr: 0x7f9733816e50, + Pos: NewPositionFromString("col:13, col:37"), + Position2: "col:37", + Type: "const char *__restrict", + Name: "__filename", + Type2: "", + IsUsed: false, + IsReferenced: false, + IsRegister: false, + ChildNodes: []Node{}, + }, + `0x7f9733817418 <> 'FILE *'`: &ParmVarDecl{ + Addr: 0x7f9733817418, + Pos: NewPositionFromString(""), + Position2: "", + Type: "FILE *", + Name: "", + Type2: "", + IsUsed: false, + IsReferenced: false, + IsRegister: false, + ChildNodes: []Node{}, + }, + `0x7f9733817c30 col:47 __size 'size_t':'unsigned long'`: &ParmVarDecl{ + Addr: 0x7f9733817c30, + Pos: NewPositionFromString("col:40, col:47"), + Position2: "col:47", + Type: "size_t", + Name: "__size", + Type2: "unsigned long", + IsUsed: false, + IsReferenced: false, + IsRegister: false, + ChildNodes: []Node{}, + }, + `0x7f973382fa10 col:34 'int (* _Nullable)(void *, char *, int)':'int (*)(void *, char *, int)'`: &ParmVarDecl{ + Addr: 0x7f973382fa10, + Pos: NewPositionFromString("line:476:18, col:25"), + Position2: "col:34", + Type: "int (* _Nullable)(void *, char *, int)", + Name: "", + Type2: "int (*)(void *, char *, int)", + IsUsed: false, + IsReferenced: false, + IsRegister: false, + ChildNodes: []Node{}, + }, + `0x7f97338355b8 col:14 used argc 'int'`: &ParmVarDecl{ + Addr: 0x7f97338355b8, + Pos: NewPositionFromString("col:10, col:14"), + Position2: "col:14", + Type: "int", + Name: "argc", + Type2: "", + IsUsed: true, + IsReferenced: false, + IsRegister: false, + ChildNodes: []Node{}, + }, + `0x1d82850 col:16 referenced foo 'char *':'char *'`: &ParmVarDecl{ + Addr: 0x1d82850, + Pos: NewPositionFromString("col:11, col:22"), + Position2: "col:16", + Type: "char *", + Name: "foo", + Type2: "char *", + IsUsed: false, + IsReferenced: true, + IsRegister: false, + ChildNodes: []Node{}, + }, + `0x7f95f30ed9d0 col:51 used eptr 'const char *' register`: &ParmVarDecl{ + Addr: 0x7f95f30ed9d0, + Pos: NewPositionFromString("col:23, col:51"), + Position2: "col:51", + Type: "const char *", + Name: "eptr", + Type2: "", + IsUsed: true, + IsReferenced: false, + IsRegister: true, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/pointer_type.go b/ast/pointer_type.go new file mode 100644 index 0000000..2c8c2e4 --- /dev/null +++ b/ast/pointer_type.go @@ -0,0 +1,44 @@ +package ast + +// PointerType is pointer type +type PointerType struct { + Addr Address + Type string + ChildNodes []Node +} + +func parsePointerType(line string) *PointerType { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &PointerType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *PointerType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *PointerType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *PointerType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *PointerType) Position() Position { + return Position{} +} diff --git a/ast/pointer_type_test.go b/ast/pointer_type_test.go new file mode 100644 index 0000000..763f679 --- /dev/null +++ b/ast/pointer_type_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestPointerType(t *testing.T) { + nodes := map[string]Node{ + `0x7fa3b88bbb30 'struct _opaque_pthread_t *'`: &PointerType{ + Addr: 0x7fa3b88bbb30, + Type: "struct _opaque_pthread_t *", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/position.go b/ast/position.go new file mode 100644 index 0000000..fb7be21 --- /dev/null +++ b/ast/position.go @@ -0,0 +1,416 @@ +package ast + +import ( + "fmt" + "path/filepath" + + "github.com/elliotchance/c2go/util" +) + +// Position is type of position in source code +type Position struct { + File string // The relative or absolute file path. + Line int // Start line + LineEnd int // End line + Column int // Start column + ColumnEnd int // End column + + // This is the original string that was converted. This is used for + // debugging. We could derive this value from the other properties to save + // on a bit of memory, but let worry about that later. + StringValue string +} + +// GetSimpleLocation - return a string like : "file:line" in +// according to position +// Example : " /tmp/1.c:200 " +func (p Position) GetSimpleLocation() (loc string) { + file := p.File + if f, err := filepath.Abs(p.File); err != nil { + file = f + } + return fmt.Sprintf(" %s:%d ", file, p.Line) +} + +func NewPositionFromString(s string) Position { + re := util.GetRegex(`||`) + if re.MatchString(s) || s == "" { + return Position{} + } + + re = util.GetRegex(`^col:(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + Column: util.Atoi(groups[1]), + } + } + + re = util.GetRegex(`^col:(\d+), col:(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + Column: util.Atoi(groups[1]), + ColumnEnd: util.Atoi(groups[2]), + } + } + + re = util.GetRegex(`^line:(\d+), line:(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + Line: util.Atoi(groups[1]), + LineEnd: util.Atoi(groups[2]), + } + } + + re = util.GetRegex(`^col:(\d+), line:(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + Column: util.Atoi(groups[1]), + Line: util.Atoi(groups[2]), + } + } + + re = util.GetRegex(`^line:(\d+):(\d+), line:(\d+):(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + Line: util.Atoi(groups[1]), + Column: util.Atoi(groups[2]), + LineEnd: util.Atoi(groups[3]), + ColumnEnd: util.Atoi(groups[4]), + } + } + + re = util.GetRegex(`^col:(\d+), line:(\d+):(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + Column: util.Atoi(groups[1]), + LineEnd: util.Atoi(groups[2]), + ColumnEnd: util.Atoi(groups[3]), + } + } + + re = util.GetRegex(`^line:(\d+):(\d+), col:(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + Line: util.Atoi(groups[1]), + Column: util.Atoi(groups[2]), + ColumnEnd: util.Atoi(groups[3]), + } + } + + re = util.GetRegex(`^line:(\d+):(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + Line: util.Atoi(groups[1]), + Column: util.Atoi(groups[2]), + } + } + + // This must be below all of the others. + re = util.GetRegex(`^([^:]+):(\d+):(\d+), col:(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + File: groups[1], + Line: util.Atoi(groups[2]), + Column: util.Atoi(groups[3]), + ColumnEnd: util.Atoi(groups[4]), + } + } + + re = util.GetRegex(`^([^:]+):(\d+):(\d+), line:(\d+):(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + File: groups[1], + Line: util.Atoi(groups[2]), + Column: util.Atoi(groups[3]), + LineEnd: util.Atoi(groups[4]), + ColumnEnd: util.Atoi(groups[5]), + } + } + + re = util.GetRegex(`^([^:]+):(\d+):(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + File: groups[1], + Line: util.Atoi(groups[2]), + Column: util.Atoi(groups[3]), + } + } + + re = util.GetRegex(`^([^:]+):(\d+):(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + File: groups[1], + Line: util.Atoi(groups[2]), + Column: util.Atoi(groups[3]), + } + } + + re = util.GetRegex(`^col:(\d+), ([^:]+):(\d+):(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + Column: util.Atoi(groups[1]), + } + } + + re = util.GetRegex(`^([^:]+):(\d+):(\d+), ([^:]+):(\d+):(\d+)$`) + if groups := re.FindStringSubmatch(s); len(groups) > 0 { + return Position{ + StringValue: s, + File: groups[1], + Line: util.Atoi(groups[2]), + Column: util.Atoi(groups[3]), + LineEnd: util.Atoi(groups[5]), + ColumnEnd: util.Atoi(groups[6]), + } + } + + panic("unable to understand position '" + s + "'") +} + +func mergePositions(p1, p2 Position) Position { + if p2.File != "" { + p1.File = p2.File + p1.Line = 0 + p1.LineEnd = 0 + p1.Column = 0 + p1.ColumnEnd = 0 + } + + if p2.Line != 0 { + p1.Line = p2.Line + p1.LineEnd = 0 + } + + if p2.LineEnd != 0 { + p1.LineEnd = p2.LineEnd + } + + if p2.Column != 0 { + p1.Column = p2.Column + p1.ColumnEnd = 0 + } + + if p2.ColumnEnd != 0 { + p1.ColumnEnd = p2.ColumnEnd + } + + return p1 +} + +var pos Position + +// PositionBuiltIn - default value for fix position +var PositionBuiltIn = "" + +func FixPositions(nodes []Node) { + pos = Position{File: PositionBuiltIn} + fixPositions(nodes) +} + +func fixPositions(nodes []Node) { + for _, node := range nodes { + if node != nil { + pos = mergePositions(pos, node.Position()) + setPosition(node, pos) + fixPositions(node.Children()) + } + } +} + +func setPosition(node Node, position Position) { + switch n := node.(type) { + case *AlignedAttr: + n.Pos = position + case *AllocSizeAttr: + n.Pos = position + case *AlwaysInlineAttr: + n.Pos = position + case *ArraySubscriptExpr: + n.Pos = position + case *AsmLabelAttr: + n.Pos = position + case *AvailabilityAttr: + n.Pos = position + case *BinaryOperator: + n.Pos = position + case *BlockCommandComment: + n.Pos = position + case *BreakStmt: + n.Pos = position + case *CallExpr: + n.Pos = position + case *CaseStmt: + n.Pos = position + case *CharacterLiteral: + n.Pos = position + case *CompoundStmt: + n.Pos = position + case *ConditionalOperator: + n.Pos = position + case *ConstAttr: + n.Pos = position + case *ContinueStmt: + n.Pos = position + case *CompoundAssignOperator: + n.Pos = position + case *CompoundLiteralExpr: + n.Pos = position + case *CStyleCastExpr: + n.Pos = position + case *DeclRefExpr: + n.Pos = position + case *DeclStmt: + n.Pos = position + case *DefaultStmt: + n.Pos = position + case *DeprecatedAttr: + n.Pos = position + case *DisableTailCallsAttr: + n.Pos = position + case *DoStmt: + n.Pos = position + case *EmptyDecl: + n.Pos = position + case *EnumConstantDecl: + n.Pos = position + case *EnumDecl: + n.Pos = position + case *FieldDecl: + n.Pos = position + case *FloatingLiteral: + n.Pos = position + case *FormatAttr: + n.Pos = position + case *FormatArgAttr: + n.Pos = position + case *FullComment: + n.Pos = position + case *FunctionDecl: + n.Pos = position + case *ForStmt: + n.Pos = position + case *GCCAsmStmt: + n.Pos = position + case *HTMLStartTagComment: + n.Pos = position + case *HTMLEndTagComment: + n.Pos = position + case *GotoStmt: + n.Pos = position + case *IfStmt: + n.Pos = position + case *ImplicitCastExpr: + n.Pos = position + case *ImplicitValueInitExpr: + n.Pos = position + case *IndirectFieldDecl: + n.Pos = position + case *InitListExpr: + n.Pos = position + case *InlineCommandComment: + n.Pos = position + case *IntegerLiteral: + n.Pos = position + case *LabelStmt: + n.Pos = position + case *MallocAttr: + n.Pos = position + case *MaxFieldAlignmentAttr: + n.Pos = position + case *MemberExpr: + n.Pos = position + case *ModeAttr: + n.Pos = position + case *NoInlineAttr: + n.Pos = position + case *NoThrowAttr: + n.Pos = position + case *NotTailCalledAttr: + n.Pos = position + case *NonNullAttr: + n.Pos = position + case *OffsetOfExpr: + n.Pos = position + case *PackedAttr: + n.Pos = position + case *ParagraphComment: + n.Pos = position + case *ParamCommandComment: + n.Pos = position + case *ParenExpr: + n.Pos = position + case *ParmVarDecl: + n.Pos = position + case *PredefinedExpr: + n.Pos = position + case *PureAttr: + n.Pos = position + case *RecordDecl: + n.Pos = position + case *RestrictAttr: + n.Pos = position + case *ReturnStmt: + n.Pos = position + case *ReturnsTwiceAttr: + n.Pos = position + case *SentinelAttr: + n.Pos = position + case *StmtExpr: + n.Pos = position + case *StringLiteral: + n.Pos = position + case *SwitchStmt: + n.Pos = position + case *TextComment: + n.Pos = position + case *TransparentUnionAttr: + n.Pos = position + case *TypedefDecl: + n.Pos = position + case *UnaryExprOrTypeTraitExpr: + n.Pos = position + case *UnaryOperator: + n.Pos = position + case *UnusedAttr: + n.Pos = position + case *VAArgExpr: + n.Pos = position + case *VarDecl: + n.Pos = position + case *VerbatimBlockComment: + n.Pos = position + case *VerbatimBlockLineComment: + n.Pos = position + case *VerbatimLineComment: + n.Pos = position + case *VisibilityAttr: + n.Pos = position + case *WarnUnusedResultAttr: + n.Pos = position + case *WeakAttr: + n.Pos = position + case *WhileStmt: + n.Pos = position + case *TypedefType, *Typedef, *TranslationUnitDecl, *RecordType, *Record, + *QualType, *PointerType, *DecayedType, *ParenType, + *IncompleteArrayType, *FunctionProtoType, *EnumType, *Enum, + *ElaboratedType, *ConstantArrayType, *BuiltinType, *ArrayFiller, + *Field: + // These do not have positions so they can be ignored. + default: + panic(fmt.Sprintf("unknown node type: %+#v", node)) + } +} diff --git a/ast/position_test.go b/ast/position_test.go new file mode 100644 index 0000000..26f21f6 --- /dev/null +++ b/ast/position_test.go @@ -0,0 +1,109 @@ +package ast + +import ( + "testing" +) + +func TestNewPositionFromString(t *testing.T) { + tests := map[string]Position{ + `col:30`: { + File: "", + Line: 0, + Column: 30, + LineEnd: 0, + ColumnEnd: 0, + }, + `col:47, col:57`: { + File: "", + Line: 0, + Column: 47, + LineEnd: 0, + ColumnEnd: 57, + }, + `/usr/include/sys/cdefs.h:313:68`: { + File: "/usr/include/sys/cdefs.h", + Line: 313, + Column: 68, + LineEnd: 0, + ColumnEnd: 0, + }, + `/usr/include/AvailabilityInternal.h:21697:88, col:124`: { + File: "/usr/include/AvailabilityInternal.h", + Line: 21697, + Column: 88, + LineEnd: 0, + ColumnEnd: 124, + }, + `line:275:50, col:99`: { + File: "", + Line: 275, + Column: 50, + LineEnd: 0, + ColumnEnd: 99, + }, + `line:11:5, line:12:21`: { + File: "", + Line: 11, + Column: 5, + LineEnd: 12, + ColumnEnd: 21, + }, + `col:54, line:358:1`: { + File: "", + Line: 0, + Column: 54, + LineEnd: 358, + ColumnEnd: 1, + }, + `/usr/include/secure/_stdio.h:42:1, line:43:32`: { + File: "/usr/include/secure/_stdio.h", + Line: 42, + Column: 1, + LineEnd: 43, + ColumnEnd: 32, + }, + `line:244:5`: { + File: "", + Line: 244, + Column: 5, + LineEnd: 0, + ColumnEnd: 0, + }, + ``: { + File: "", + Line: 0, + Column: 0, + LineEnd: 0, + ColumnEnd: 0, + }, + `/usr/include/sys/stdio.h:39:1, /usr/include/AvailabilityInternal.h:21697:126`: { + File: "/usr/include/sys/stdio.h", + Line: 39, + Column: 1, + LineEnd: 0, + ColumnEnd: 0, + }, + `col:1, /usr/include/sys/cdefs.h:351:63`: { + File: "", + Line: 0, + Column: 1, + LineEnd: 0, + ColumnEnd: 0, + }, + } + + for testName, expectedPos := range tests { + t.Run(testName, func(t *testing.T) { + pos := NewPositionFromString(testName) + if pos.File != expectedPos.File { + t.Errorf("TestNewPositionFromString: File: %#v != %#v", pos.File, expectedPos.File) + } + if pos.Line != expectedPos.Line { + t.Errorf("TestNewPositionFromString: Line: %#v != %#v", pos.Line, expectedPos.Line) + } + if pos.Column != expectedPos.Column { + t.Errorf("TestNewPositionFromString: Column: %#v != %#v", pos.Column, expectedPos.Column) + } + }) + } +} diff --git a/ast/predefined_expr.go b/ast/predefined_expr.go new file mode 100644 index 0000000..4499562 --- /dev/null +++ b/ast/predefined_expr.go @@ -0,0 +1,50 @@ +package ast + +// PredefinedExpr is expression. +type PredefinedExpr struct { + Addr Address + Pos Position + Type string + Name string + Lvalue bool + ChildNodes []Node +} + +func parsePredefinedExpr(line string) *PredefinedExpr { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*)' lvalue (?P.*)", + line, + ) + + return &PredefinedExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Name: groups["name"], + Lvalue: true, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *PredefinedExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *PredefinedExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *PredefinedExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *PredefinedExpr) Position() Position { + return n.Pos +} diff --git a/ast/predefined_expr_test.go b/ast/predefined_expr_test.go new file mode 100644 index 0000000..d9ffc4c --- /dev/null +++ b/ast/predefined_expr_test.go @@ -0,0 +1,20 @@ +package ast + +import ( + "testing" +) + +func TestPredefinedExpr(t *testing.T) { + nodes := map[string]Node{ + `0x33d6e08 'const char [25]' lvalue __PRETTY_FUNCTION__`: &PredefinedExpr{ + Addr: 0x33d6e08, + Pos: NewPositionFromString("col:30"), + Type: "const char [25]", + Lvalue: true, + Name: "__PRETTY_FUNCTION__", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/pure_attr.go b/ast/pure_attr.go new file mode 100644 index 0000000..6b7bc57 --- /dev/null +++ b/ast/pure_attr.go @@ -0,0 +1,51 @@ +package ast + +// PureAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type PureAttr struct { + Addr Address + Pos Position + Implicit bool + Inherited bool + ChildNodes []Node +} + +func parsePureAttr(line string) *PureAttr { + groups := groupsFromRegex( + `<(?P.*)> + (?P Inherited)? + (?P Implicit)?`, + line, + ) + + return &PureAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Implicit: len(groups["implicit"]) > 0, + Inherited: len(groups["inherited"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *PureAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *PureAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *PureAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *PureAttr) Position() Position { + return n.Pos +} diff --git a/ast/pure_attr_test.go b/ast/pure_attr_test.go new file mode 100644 index 0000000..b590e89 --- /dev/null +++ b/ast/pure_attr_test.go @@ -0,0 +1,26 @@ +package ast + +import ( + "testing" +) + +func TestPureAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fe9eb899198 Implicit`: &PureAttr{ + Addr: 0x7fe9eb899198, + Pos: NewPositionFromString("col:1"), + Implicit: true, + Inherited: false, + ChildNodes: []Node{}, + }, + `0x7fe8d60992a0 Inherited Implicit`: &PureAttr{ + Addr: 0x7fe8d60992a0, + Pos: NewPositionFromString("col:1"), + Implicit: true, + Inherited: true, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/qual_type.go b/ast/qual_type.go new file mode 100644 index 0000000..e53b44a --- /dev/null +++ b/ast/qual_type.go @@ -0,0 +1,46 @@ +package ast + +// QualType is qual type +type QualType struct { + Addr Address + Type string + Kind string + ChildNodes []Node +} + +func parseQualType(line string) *QualType { + groups := groupsFromRegex( + "'(?P.*)' (?P.*)", + line, + ) + + return &QualType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + Kind: groups["kind"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *QualType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *QualType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *QualType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *QualType) Position() Position { + return Position{} +} diff --git a/ast/qual_type_test.go b/ast/qual_type_test.go new file mode 100644 index 0000000..80d41f8 --- /dev/null +++ b/ast/qual_type_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestQualType(t *testing.T) { + nodes := map[string]Node{ + `0x7fa3b88bbb31 'struct _opaque_pthread_t *' foo`: &QualType{ + Addr: 0x7fa3b88bbb31, + Type: "struct _opaque_pthread_t *", + Kind: "foo", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/record.go b/ast/record.go new file mode 100644 index 0000000..4f29018 --- /dev/null +++ b/ast/record.go @@ -0,0 +1,44 @@ +package ast + +// Record struct +type Record struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseRecord(line string) *Record { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &Record{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *Record) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *Record) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *Record) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *Record) Position() Position { + return Position{} +} diff --git a/ast/record_decl.go b/ast/record_decl.go new file mode 100644 index 0000000..8ce85ac --- /dev/null +++ b/ast/record_decl.go @@ -0,0 +1,74 @@ +package ast + +import ( + "strings" +) + +// RecordDecl is node represents a record declaration. +type RecordDecl struct { + Addr Address + Pos Position + Prev string + Position2 string + Kind string + Name string + Definition bool + ChildNodes []Node +} + +func parseRecordDecl(line string) *RecordDecl { + groups := groupsFromRegex( + `(?:parent (?P0x[0-9a-f]+) )? + (?:prev (?P0x[0-9a-f]+) )? + <(?P.*)> + [ ](?P[^ ]+ )? + (?Pstruct|union) + (?P.*)`, + line, + ) + + definition := false + name := strings.TrimSpace(groups["name"]) + if name == "definition" { + name = "" + definition = true + } + if strings.HasSuffix(name, " definition") { + name = name[0 : len(name)-11] + definition = true + } + + return &RecordDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Prev: groups["prev"], + Position2: strings.TrimSpace(groups["position2"]), + Kind: groups["kind"], + Name: name, + Definition: definition, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *RecordDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *RecordDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *RecordDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *RecordDecl) Position() Position { + return n.Pos +} diff --git a/ast/record_decl_test.go b/ast/record_decl_test.go new file mode 100644 index 0000000..e887f67 --- /dev/null +++ b/ast/record_decl_test.go @@ -0,0 +1,62 @@ +package ast + +import ( + "testing" +) + +func TestRecordDecl(t *testing.T) { + nodes := map[string]Node{ + `0x7f913c0dbb50 line:76:9 union definition`: &RecordDecl{ + Addr: 0x7f913c0dbb50, + Pos: NewPositionFromString("line:76:9, line:79:1"), + Prev: "", + Position2: "line:76:9", + Kind: "union", + Name: "", + Definition: true, + ChildNodes: []Node{}, + }, + `0x7f85360285c8 line:57:8 struct __darwin_pthread_handler_rec definition`: &RecordDecl{ + Addr: 0x7f85360285c8, + Pos: NewPositionFromString("/usr/include/sys/_pthread/_pthread_types.h:57:1, line:61:1"), + Prev: "", + Position2: "line:57:8", + Kind: "struct", + Name: "__darwin_pthread_handler_rec", + Definition: true, + ChildNodes: []Node{}, + }, + `0x7f85370248a0 col:8 struct __sFILEX`: &RecordDecl{ + Addr: 0x7f85370248a0, + Pos: NewPositionFromString("line:94:1, col:8"), + Prev: "", + Position2: "col:8", + Kind: "struct", + Name: "__sFILEX", + Definition: false, + ChildNodes: []Node{}, + }, + `0x5564ed488a10 parent 0x5564ed3ffe00 line:7232:10 struct sqlite3_index_constraint definition`: &RecordDecl{ + Addr: 0x5564ed488a10, + Pos: NewPositionFromString("line:7232:3, line:7237:3"), + Prev: "", + Position2: "line:7232:10", + Kind: "struct", + Name: "sqlite3_index_constraint", + Definition: true, + ChildNodes: []Node{}, + }, + `0x56454e55e4b8 prev 0x56454e55e360 line:86428:8 struct Incrblob definition`: &RecordDecl{ + Addr: 0x56454e55e4b8, + Pos: NewPositionFromString("line:86428:1, line:86437:1"), + Prev: "0x56454e55e360", + Position2: "line:86428:8", + Kind: "struct", + Name: "Incrblob", + Definition: true, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/record_test.go b/ast/record_test.go new file mode 100644 index 0000000..be12fd8 --- /dev/null +++ b/ast/record_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestRecord(t *testing.T) { + nodes := map[string]Node{ + `0x7fd3ab857950 '__sFILE'`: &Record{ + Addr: 0x7fd3ab857950, + Type: "__sFILE", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/record_type.go b/ast/record_type.go new file mode 100644 index 0000000..41d442b --- /dev/null +++ b/ast/record_type.go @@ -0,0 +1,44 @@ +package ast + +// RecordType is record type +type RecordType struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseRecordType(line string) *RecordType { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &RecordType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *RecordType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *RecordType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *RecordType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *RecordType) Position() Position { + return Position{} +} diff --git a/ast/record_type_test.go b/ast/record_type_test.go new file mode 100644 index 0000000..f1dffb6 --- /dev/null +++ b/ast/record_type_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestRecordType(t *testing.T) { + nodes := map[string]Node{ + `0x7fd3ab84dda0 'struct _opaque_pthread_condattr_t'`: &RecordType{ + Addr: 0x7fd3ab84dda0, + Type: "struct _opaque_pthread_condattr_t", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/restrict_attr.go b/ast/restrict_attr.go new file mode 100644 index 0000000..18463f0 --- /dev/null +++ b/ast/restrict_attr.go @@ -0,0 +1,47 @@ +package ast + +// RestrictAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type RestrictAttr struct { + Addr Address + Pos Position + Name string + ChildNodes []Node +} + +func parseRestrictAttr(line string) *RestrictAttr { + groups := groupsFromRegex( + "<(?P.*)> (?P.+)", + line, + ) + + return &RestrictAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Name: groups["name"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *RestrictAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *RestrictAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *RestrictAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *RestrictAttr) Position() Position { + return n.Pos +} diff --git a/ast/restrict_attr_test.go b/ast/restrict_attr_test.go new file mode 100644 index 0000000..5ed5443 --- /dev/null +++ b/ast/restrict_attr_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestRestrictAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7f980b858305 foo`: &RestrictAttr{ + Addr: 0x7f980b858305, + Pos: NewPositionFromString("line:11:7, line:18:7"), + Name: "foo", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/return_stmt.go b/ast/return_stmt.go new file mode 100644 index 0000000..da9d11b --- /dev/null +++ b/ast/return_stmt.go @@ -0,0 +1,44 @@ +package ast + +// ReturnStmt is node represent 'return' +type ReturnStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseReturnStmt(line string) *ReturnStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &ReturnStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ReturnStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ReturnStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ReturnStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ReturnStmt) Position() Position { + return n.Pos +} diff --git a/ast/return_stmt_test.go b/ast/return_stmt_test.go new file mode 100644 index 0000000..f453409 --- /dev/null +++ b/ast/return_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestReturnStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fbb7a8325e0 `: &ReturnStmt{ + Addr: 0x7fbb7a8325e0, + Pos: NewPositionFromString("line:13:4, col:11"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/returns_twice_attr.go b/ast/returns_twice_attr.go new file mode 100644 index 0000000..8266440 --- /dev/null +++ b/ast/returns_twice_attr.go @@ -0,0 +1,52 @@ +package ast + +// ReturnsTwiceAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type ReturnsTwiceAttr struct { + Addr Address + Pos Position + ChildNodes []Node + Inherited bool + Implicit bool +} + +func parseReturnsTwiceAttr(line string) *ReturnsTwiceAttr { + groups := groupsFromRegex( + `<(?P.*)> + (?P Inherited)? + (?P Implicit)? + `, + line, + ) + + return &ReturnsTwiceAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + Inherited: len(groups["inherited"]) > 0, + Implicit: len(groups["implicit"]) > 0, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *ReturnsTwiceAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *ReturnsTwiceAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *ReturnsTwiceAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *ReturnsTwiceAttr) Position() Position { + return n.Pos +} diff --git a/ast/returns_twice_attr_test.go b/ast/returns_twice_attr_test.go new file mode 100644 index 0000000..2e87bae --- /dev/null +++ b/ast/returns_twice_attr_test.go @@ -0,0 +1,26 @@ +package ast + +import ( + "testing" +) + +func TestReturnsTwiceAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7ff8e9091640 Implicit`: &ReturnsTwiceAttr{ + Addr: 0x7ff8e9091640, + Pos: NewPositionFromString("col:7"), + ChildNodes: []Node{}, + Inherited: false, + Implicit: true, + }, + `0x564a73a5ccc8 Inherited Implicit`: &ReturnsTwiceAttr{ + Addr: 0x564a73a5ccc8, + Pos: NewPositionFromString("col:16"), + ChildNodes: []Node{}, + Inherited: true, + Implicit: true, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/sentinel_attr.go b/ast/sentinel_attr.go new file mode 100644 index 0000000..044a5d8 --- /dev/null +++ b/ast/sentinel_attr.go @@ -0,0 +1,60 @@ +package ast + +import ( + "strings" + + "github.com/elliotchance/c2go/util" +) + +// SentinelAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type SentinelAttr struct { + Addr Address + Pos Position + A int + B int + ChildNodes []Node +} + +func parseSentinelAttr(line string) *SentinelAttr { + groups := groupsFromRegex( + `<(?P.*)>(?P \d+)(?P \d+)?`, + line, + ) + + b := 0 + if groups["b"] != "" { + b = util.Atoi(strings.TrimSpace(groups["b"])) + } + + return &SentinelAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + A: util.Atoi(strings.TrimSpace(groups["a"])), + B: b, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *SentinelAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *SentinelAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *SentinelAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *SentinelAttr) Position() Position { + return n.Pos +} diff --git a/ast/sentinel_attr_test.go b/ast/sentinel_attr_test.go new file mode 100644 index 0000000..e30546e --- /dev/null +++ b/ast/sentinel_attr_test.go @@ -0,0 +1,19 @@ +package ast + +import ( + "testing" +) + +func TestSentinelAttr(t *testing.T) { + nodes := map[string]Node{ + `0x346df70 0 0`: &SentinelAttr{ + Addr: 0x346df70, + Pos: NewPositionFromString("line:3571:19, col:33"), + A: 0, + B: 0, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/stmt_expr.go b/ast/stmt_expr.go new file mode 100644 index 0000000..5b40a40 --- /dev/null +++ b/ast/stmt_expr.go @@ -0,0 +1,46 @@ +package ast + +// StmtExpr is expression. +type StmtExpr struct { + Addr Address + Pos Position + Type string + ChildNodes []Node +} + +func parseStmtExpr(line string) *StmtExpr { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*)'", + line, + ) + + return &StmtExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *StmtExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *StmtExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *StmtExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *StmtExpr) Position() Position { + return n.Pos +} diff --git a/ast/stmt_expr_test.go b/ast/stmt_expr_test.go new file mode 100644 index 0000000..6cf670c --- /dev/null +++ b/ast/stmt_expr_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestStmtExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7ff4f9100d28 'int'`: &StmtExpr{ + Addr: 0x7ff4f9100d28, + Pos: NewPositionFromString("col:11, col:18"), + Type: "int", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/string_literal.go b/ast/string_literal.go new file mode 100644 index 0000000..8b9eef5 --- /dev/null +++ b/ast/string_literal.go @@ -0,0 +1,60 @@ +package ast + +import ( + "fmt" + "strconv" +) + +// StringLiteral is type of string literal +type StringLiteral struct { + Addr Address + Pos Position + Type string + Value string + Lvalue bool + ChildNodes []Node +} + +func parseStringLiteral(line string) *StringLiteral { + groups := groupsFromRegex( + `<(?P.*)> '(?P.*)' lvalue (?P".*")`, + line, + ) + + s, err := strconv.Unquote(groups["value"]) + if err != nil { + panic(fmt.Sprintf("Unable to unquote %s\n", groups["value"])) + } + + return &StringLiteral{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Value: s, + Lvalue: true, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *StringLiteral) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *StringLiteral) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *StringLiteral) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *StringLiteral) Position() Position { + return n.Pos +} diff --git a/ast/string_literal_test.go b/ast/string_literal_test.go new file mode 100644 index 0000000..304630f --- /dev/null +++ b/ast/string_literal_test.go @@ -0,0 +1,28 @@ +package ast + +import ( + "testing" +) + +func TestStringLiteral(t *testing.T) { + nodes := map[string]Node{ + `0x7fe16f0b4d58 'char [45]' lvalue "Number of command line arguments passed: %d\n"`: &StringLiteral{ + Addr: 0x7fe16f0b4d58, + Pos: NewPositionFromString("col:11"), + Type: "char [45]", + Lvalue: true, + Value: "Number of command line arguments passed: %d\n", + ChildNodes: []Node{}, + }, + `0x22ac548 'char [14]' lvalue "x\vx\000xxx\axx\tx\n"`: &StringLiteral{ + Addr: 0x22ac548, + Pos: NewPositionFromString("col:14"), + Type: "char [14]", + Lvalue: true, + Value: "x\vx\x00xxx\axx\tx\n", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/switch_stmt.go b/ast/switch_stmt.go new file mode 100644 index 0000000..b89ac29 --- /dev/null +++ b/ast/switch_stmt.go @@ -0,0 +1,41 @@ +package ast + +// SwitchStmt is node represent 'switch' +type SwitchStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseSwitchStmt(line string) *SwitchStmt { + groups := groupsFromRegex(`<(?P.*)>`, line) + + return &SwitchStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *SwitchStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *SwitchStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *SwitchStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *SwitchStmt) Position() Position { + return n.Pos +} diff --git a/ast/switch_stmt_test.go b/ast/switch_stmt_test.go new file mode 100644 index 0000000..edd0431 --- /dev/null +++ b/ast/switch_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestSwitchStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fbca3894638 `: &SwitchStmt{ + Addr: 0x7fbca3894638, + Pos: NewPositionFromString("line:9:5, line:20:5"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/text_comment.go b/ast/text_comment.go new file mode 100644 index 0000000..1187946 --- /dev/null +++ b/ast/text_comment.go @@ -0,0 +1,46 @@ +package ast + +// TextComment is a type of comment +type TextComment struct { + Addr Address + Pos Position + Text string + ChildNodes []Node +} + +func parseTextComment(line string) *TextComment { + groups := groupsFromRegex( + `<(?P.*)> Text="(?P.*)"`, + line, + ) + + return &TextComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Text: groups["text"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *TextComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *TextComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *TextComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *TextComment) Position() Position { + return n.Pos +} diff --git a/ast/text_comment_test.go b/ast/text_comment_test.go new file mode 100644 index 0000000..f32cb27 --- /dev/null +++ b/ast/text_comment_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestTextComment(t *testing.T) { + nodes := map[string]Node{ + `0x3085bc0 Text="* CUSTOM AUXILIARY FUNCTIONS"`: &TextComment{ + Addr: 0x3085bc0, + Pos: NewPositionFromString("line:9950:2, col:29"), + Text: "* CUSTOM AUXILIARY FUNCTIONS", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/translation_unit_decl.go b/ast/translation_unit_decl.go new file mode 100644 index 0000000..4656327 --- /dev/null +++ b/ast/translation_unit_decl.go @@ -0,0 +1,39 @@ +package ast + +// TranslationUnitDecl is node represents a translation unit declaration. +type TranslationUnitDecl struct { + Addr Address + ChildNodes []Node +} + +func parseTranslationUnitDecl(line string) *TranslationUnitDecl { + groups := groupsFromRegex("<(?P.*)> <(?P.*)>", line) + + return &TranslationUnitDecl{ + Addr: ParseAddress(groups["address"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *TranslationUnitDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *TranslationUnitDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *TranslationUnitDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *TranslationUnitDecl) Position() Position { + return Position{} +} diff --git a/ast/translation_unit_decl_test.go b/ast/translation_unit_decl_test.go new file mode 100644 index 0000000..079f5e5 --- /dev/null +++ b/ast/translation_unit_decl_test.go @@ -0,0 +1,16 @@ +package ast + +import ( + "testing" +) + +func TestTranslationUnitDecl(t *testing.T) { + nodes := map[string]Node{ + `0x7fe78a815ed0 <> `: &TranslationUnitDecl{ + Addr: 0x7fe78a815ed0, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/transparent_union_attr.go b/ast/transparent_union_attr.go new file mode 100644 index 0000000..2a419f1 --- /dev/null +++ b/ast/transparent_union_attr.go @@ -0,0 +1,42 @@ +package ast + +// TransparentUnionAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type TransparentUnionAttr struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseTransparentUnionAttr(line string) *TransparentUnionAttr { + groups := groupsFromRegex(`<(?P.*)>`, line) + + return &TransparentUnionAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *TransparentUnionAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *TransparentUnionAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *TransparentUnionAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *TransparentUnionAttr) Position() Position { + return n.Pos +} diff --git a/ast/transparent_union_attr_test.go b/ast/transparent_union_attr_test.go new file mode 100644 index 0000000..c9aa28e --- /dev/null +++ b/ast/transparent_union_attr_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestTransparentUnionAttr(t *testing.T) { + nodes := map[string]Node{ + `0x304f700 `: &TransparentUnionAttr{ + Addr: 0x304f700, + Pos: NewPositionFromString("col:35"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/traverse.go b/ast/traverse.go new file mode 100644 index 0000000..c2efc1a --- /dev/null +++ b/ast/traverse.go @@ -0,0 +1,28 @@ +package ast + +import ( + "reflect" +) + +// GetAllNodesOfType returns all of the nodes of the tree that match the type +// provided. The type should be a pointer to an object in the ast package. +// +// The nodes returned may reference each other and there is no guaranteed order +// in which the nodes are returned. +func GetAllNodesOfType(root Node, t reflect.Type) []Node { + nodes := []Node{} + + if root == nil { + return []Node{} + } + + if reflect.TypeOf(root) == t { + nodes = append(nodes, root) + } + + for _, c := range root.Children() { + nodes = append(nodes, GetAllNodesOfType(c, t)...) + } + + return nodes +} diff --git a/ast/typedef.go b/ast/typedef.go new file mode 100644 index 0000000..1f760ad --- /dev/null +++ b/ast/typedef.go @@ -0,0 +1,44 @@ +package ast + +// Typedef struct +type Typedef struct { + Addr Address + Type string + ChildNodes []Node +} + +func parseTypedef(line string) *Typedef { + groups := groupsFromRegex( + "'(?P.*)'", + line, + ) + + return &Typedef{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *Typedef) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *Typedef) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *Typedef) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *Typedef) Position() Position { + return Position{} +} diff --git a/ast/typedef_decl.go b/ast/typedef_decl.go new file mode 100644 index 0000000..2561a1c --- /dev/null +++ b/ast/typedef_decl.go @@ -0,0 +1,72 @@ +package ast + +import ( + "strings" +) + +// TypedefDecl is node represents a typedef declaration. +type TypedefDecl struct { + Addr Address + Pos Position + Position2 string + Name string + Type string + Type2 string + IsImplicit bool + IsReferenced bool + ChildNodes []Node +} + +func parseTypedefDecl(line string) *TypedefDecl { + groups := groupsFromRegex( + `(?:prev (?P0x[0-9a-f]+) )? + <(?P|.*?)> + (?P | col:\d+| line:\d+:\d+)? + (?P implicit)? + (?P referenced)? + (?P \w+)? + (?P '.*?')? + (?P:'.*?')?`, + line, + ) + + type2 := groups["type2"] + if type2 != "" { + type2 = type2[2 : len(type2)-1] + } + + return &TypedefDecl{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: strings.TrimSpace(groups["position2"]), + Name: strings.TrimSpace(groups["name"]), + Type: removeQuotes(groups["type"]), + Type2: type2, + IsImplicit: len(groups["implicit"]) > 0, + IsReferenced: len(groups["referenced"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *TypedefDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *TypedefDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *TypedefDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *TypedefDecl) Position() Position { + return n.Pos +} diff --git a/ast/typedef_decl_test.go b/ast/typedef_decl_test.go new file mode 100644 index 0000000..d6423a5 --- /dev/null +++ b/ast/typedef_decl_test.go @@ -0,0 +1,100 @@ +package ast + +import ( + "testing" +) + +func TestTypedefDecl(t *testing.T) { + nodes := map[string]Node{ + `0x7fdef0862430 col:16`: &TypedefDecl{ + Addr: 0x7fdef0862430, + Pos: NewPositionFromString("line:120:1, col:16"), + Position2: "col:16", + Name: "", + Type: "", + Type2: "", + IsImplicit: false, + IsReferenced: false, + ChildNodes: []Node{}, + }, + `0x7ffb9f824278 <> implicit __uint128_t 'unsigned __int128'`: &TypedefDecl{ + Addr: 0x7ffb9f824278, + Pos: NewPositionFromString(""), + Position2: "", + Name: "__uint128_t", + Type: "unsigned __int128", + Type2: "", + IsImplicit: true, + IsReferenced: false, + ChildNodes: []Node{}, + }, + `0x7ffb9f824898 <> implicit referenced __builtin_va_list 'struct __va_list_tag [1]'`: &TypedefDecl{ + Addr: 0x7ffb9f824898, + Pos: NewPositionFromString(""), + Position2: "", + Name: "__builtin_va_list", + Type: "struct __va_list_tag [1]", + Type2: "", + IsImplicit: true, + IsReferenced: true, + ChildNodes: []Node{}, + }, + `0x7ffb9f8248f8 col:24 __int8_t 'signed char'`: &TypedefDecl{ + Addr: 0x7ffb9f8248f8, + Pos: NewPositionFromString("/usr/include/i386/_types.h:37:1, col:24"), + Position2: "col:24", + Name: "__int8_t", + Type: "signed char", + Type2: "", + IsImplicit: false, + IsReferenced: false, + ChildNodes: []Node{}, + }, + `0x7ffb9f8dbf50 col:27 referenced __darwin_va_list '__builtin_va_list':'struct __va_list_tag [1]'`: &TypedefDecl{ + Addr: 0x7ffb9f8dbf50, + Pos: NewPositionFromString("line:98:1, col:27"), + Position2: "col:27", + Name: "__darwin_va_list", + Type: "__builtin_va_list", + Type2: "struct __va_list_tag [1]", + IsImplicit: false, + IsReferenced: true, + ChildNodes: []Node{}, + }, + `0x34461f0 __io_read_fn '__ssize_t (void *, char *, size_t)'`: &TypedefDecl{ + Addr: 0x34461f0, + Pos: NewPositionFromString("line:338:1, col:77"), + Position2: "", + Name: "__io_read_fn", + Type: "__ssize_t (void *, char *, size_t)", + Type2: "", + IsImplicit: false, + IsReferenced: false, + ChildNodes: []Node{}, + }, + `0x55b9da8784b0 line:341:19 __io_write_fn '__ssize_t (void *, const char *, size_t)'`: &TypedefDecl{ + Addr: 0x55b9da8784b0, + Pos: NewPositionFromString("line:341:1, line:342:16"), + Position2: "line:341:19", + Name: "__io_write_fn", + Type: "__ssize_t (void *, const char *, size_t)", + Type2: "", + IsImplicit: false, + IsReferenced: false, + ChildNodes: []Node{}, + }, + `0x3f0b9b0 col:3 referenced extCoord 'struct extCoord':'extCoord'`: &TypedefDecl{ + Addr: 0x3f0b9b0, + Pos: NewPositionFromString("line:12:1, line:15:3"), + Position2: "col:3", + Name: "extCoord", + Type: "struct extCoord", + Type2: "extCoord", + IsImplicit: false, + IsReferenced: true, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/typedef_test.go b/ast/typedef_test.go new file mode 100644 index 0000000..f7ec9e0 --- /dev/null +++ b/ast/typedef_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestTypedef(t *testing.T) { + nodes := map[string]Node{ + `0x7f84d10dc1d0 '__darwin_ssize_t'`: &Typedef{ + Addr: 0x7f84d10dc1d0, + Type: "__darwin_ssize_t", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/typedef_type.go b/ast/typedef_type.go new file mode 100644 index 0000000..d8f03ec --- /dev/null +++ b/ast/typedef_type.go @@ -0,0 +1,46 @@ +package ast + +// TypedefType is typedef type +type TypedefType struct { + Addr Address + Type string + Tags string + ChildNodes []Node +} + +func parseTypedefType(line string) *TypedefType { + groups := groupsFromRegex( + "'(?P.*)' (?P.+)", + line, + ) + + return &TypedefType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + Tags: groups["tags"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *TypedefType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *TypedefType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *TypedefType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *TypedefType) Position() Position { + return Position{} +} diff --git a/ast/typedef_type_test.go b/ast/typedef_type_test.go new file mode 100644 index 0000000..9662c45 --- /dev/null +++ b/ast/typedef_type_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestTypedefType(t *testing.T) { + nodes := map[string]Node{ + `0x7f887a0dc760 '__uint16_t' sugar`: &TypedefType{ + Addr: 0x7f887a0dc760, + Type: "__uint16_t", + Tags: "sugar", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/unary_expr_or_type_trait_expr.go b/ast/unary_expr_or_type_trait_expr.go new file mode 100644 index 0000000..15f5256 --- /dev/null +++ b/ast/unary_expr_or_type_trait_expr.go @@ -0,0 +1,57 @@ +package ast + +// UnaryExprOrTypeTraitExpr is expression. +type UnaryExprOrTypeTraitExpr struct { + Addr Address + Pos Position + Type1 string + Function string + Type2 string + Type3 string + ChildNodes []Node +} + +func parseUnaryExprOrTypeTraitExpr(line string) *UnaryExprOrTypeTraitExpr { + groups := groupsFromRegex( + `<(?P.*)> + '(?P.+?)' + (?P[^ ]+) + (?P '.+?')? + (:'(?P.*?)')? + `, + line, + ) + + return &UnaryExprOrTypeTraitExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type1: groups["type1"], + Function: groups["function"], + Type2: removeQuotes(groups["type2"]), + Type3: groups["type3"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *UnaryExprOrTypeTraitExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *UnaryExprOrTypeTraitExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *UnaryExprOrTypeTraitExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *UnaryExprOrTypeTraitExpr) Position() Position { + return n.Pos +} diff --git a/ast/unary_expr_or_type_trait_expr_test.go b/ast/unary_expr_or_type_trait_expr_test.go new file mode 100644 index 0000000..0519a39 --- /dev/null +++ b/ast/unary_expr_or_type_trait_expr_test.go @@ -0,0 +1,48 @@ +package ast + +import ( + "testing" +) + +func TestUnaryExprOrTypeTraitExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7fccd70adf50 'unsigned long' sizeof 'char'`: &UnaryExprOrTypeTraitExpr{ + Addr: 0x7fccd70adf50, + Pos: NewPositionFromString("col:29, col:40"), + Type1: "unsigned long", + Function: "sizeof", + Type2: "char", + Type3: "", + ChildNodes: []Node{}, + }, + `0x7fae1a800190 'unsigned long' sizeof`: &UnaryExprOrTypeTraitExpr{ + Addr: 0x7fae1a800190, + Pos: NewPositionFromString("col:36, col:44"), + Type1: "unsigned long", + Function: "sizeof", + Type2: "", + Type3: "", + ChildNodes: []Node{}, + }, + `0x557e575e70b8 'unsigned long' sizeof 'union MyUnion':'union MyUnion'`: &UnaryExprOrTypeTraitExpr{ + Addr: 0x557e575e70b8, + Pos: NewPositionFromString("col:432, col:452"), + Type1: "unsigned long", + Function: "sizeof", + Type2: "union MyUnion", + Type3: "union MyUnion", + ChildNodes: []Node{}, + }, + `0x3f142d8 'unsigned long' sizeof 'extCoord':'extCoord'`: &UnaryExprOrTypeTraitExpr{ + Addr: 0x3f142d8, + Pos: NewPositionFromString("col:30, col:45"), + Type1: "unsigned long", + Function: "sizeof", + Type2: "extCoord", + Type3: "extCoord", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/unary_operator.go b/ast/unary_operator.go new file mode 100644 index 0000000..d2de9da --- /dev/null +++ b/ast/unary_operator.go @@ -0,0 +1,59 @@ +package ast + +// UnaryOperator is type of unary operator +type UnaryOperator struct { + Addr Address + Pos Position + Type string + Type2 string + IsLvalue bool + IsPrefix bool + Operator string + ChildNodes []Node +} + +func parseUnaryOperator(line string) *UnaryOperator { + groups := groupsFromRegex( + `<(?P.*)> + '(?P.*?)'(:'(?P.*)')? + (?P lvalue)? + (?P prefix)? + (?P postfix)? + '(?P.*?)'`, + line, + ) + + return &UnaryOperator{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + Type2: groups["type2"], + IsLvalue: len(groups["lvalue"]) > 0, + IsPrefix: len(groups["prefix"]) > 0, + Operator: groups["operator"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *UnaryOperator) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *UnaryOperator) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *UnaryOperator) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *UnaryOperator) Position() Position { + return n.Pos +} diff --git a/ast/unary_operator_test.go b/ast/unary_operator_test.go new file mode 100644 index 0000000..7549c09 --- /dev/null +++ b/ast/unary_operator_test.go @@ -0,0 +1,52 @@ +package ast + +import ( + "testing" +) + +func TestUnaryOperator(t *testing.T) { + nodes := map[string]Node{ + `0x7fe0260f50d8 'int' prefix '--'`: &UnaryOperator{ + Addr: 0x7fe0260f50d8, + Pos: NewPositionFromString("col:6, col:12"), + Type: "int", + Type2: "", + IsLvalue: false, + IsPrefix: true, + Operator: "--", + ChildNodes: []Node{}, + }, + `0x7fe0260fb468 'unsigned char' lvalue prefix '*'`: &UnaryOperator{ + Addr: 0x7fe0260fb468, + Pos: NewPositionFromString("col:11, col:18"), + Type: "unsigned char", + Type2: "", + IsLvalue: true, + IsPrefix: true, + Operator: "*", + ChildNodes: []Node{}, + }, + `0x7fe0260fb448 'unsigned char *' postfix '++'`: &UnaryOperator{ + Addr: 0x7fe0260fb448, + Pos: NewPositionFromString("col:12, col:18"), + Type: "unsigned char *", + Type2: "", + IsLvalue: false, + IsPrefix: false, + Operator: "++", + ChildNodes: []Node{}, + }, + `0x26fd2b8 'extCoord':'extCoord' lvalue prefix '*'`: &UnaryOperator{ + Addr: 0x26fd2b8, + Pos: NewPositionFromString("col:20, col:32"), + Type: "extCoord", + Type2: "extCoord", + IsLvalue: true, + IsPrefix: true, + Operator: "*", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/unknown.go b/ast/unknown.go new file mode 100644 index 0000000..63138db --- /dev/null +++ b/ast/unknown.go @@ -0,0 +1,60 @@ +package ast + +import ( + "strings" +) + +// Unknown is node represents an unknown node. +type Unknown struct { + Name string + Addr Address + Pos Position + Position2 string + Content string + ChildNodes []Node +} + +func parseUnknown(name, line string) *Unknown { + groups := groupsFromRegex( + `(?:prev (?P0x[0-9a-f]+) )? + <(?P.*.*?|.*.*?|.*|.*?)> + (?P | col:\d+| line:\d+:\d+)? + (?P.*)`, + line, + ) +/* + (?P | col:\d+| line:\d+:\d+)? +*/ + + return &Unknown{ + Name: name, + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Position2: strings.TrimSpace(groups["position2"]), + Content: groups["content"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *Unknown) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *Unknown) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *Unknown) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *Unknown) Position() Position { + return n.Pos +} diff --git a/ast/unused_attr.go b/ast/unused_attr.go new file mode 100644 index 0000000..dbf79c9 --- /dev/null +++ b/ast/unused_attr.go @@ -0,0 +1,47 @@ +package ast + +// UnusedAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type UnusedAttr struct { + Addr Address + Pos Position + ChildNodes []Node + IsUnused bool +} + +func parseUnusedAttr(line string) *UnusedAttr { + groups := groupsFromRegex( + "<(?P.*)>(?P unused)?", + line, + ) + + return &UnusedAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + IsUnused: len(groups["unused"]) > 0, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *UnusedAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *UnusedAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *UnusedAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *UnusedAttr) Position() Position { + return n.Pos +} diff --git a/ast/unused_attr_test.go b/ast/unused_attr_test.go new file mode 100644 index 0000000..7463c9a --- /dev/null +++ b/ast/unused_attr_test.go @@ -0,0 +1,24 @@ +package ast + +import ( + "testing" +) + +func TestUnusedAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fe3e01416d0 unused`: &UnusedAttr{ + Addr: 0x7fe3e01416d0, + Pos: NewPositionFromString("col:47"), + ChildNodes: []Node{}, + IsUnused: true, + }, + `0x7fe3e01416d0 `: &UnusedAttr{ + Addr: 0x7fe3e01416d0, + Pos: NewPositionFromString("col:47"), + ChildNodes: []Node{}, + IsUnused: false, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/util.go b/ast/util.go new file mode 100644 index 0000000..07a6b6f --- /dev/null +++ b/ast/util.go @@ -0,0 +1,82 @@ +package ast + +import ( + "bytes" + "encoding/json" + "fmt" + "strconv" + "strings" +) + +func removeQuotes(s string) string { + s = strings.TrimSpace(s) + + if s == `""` { + return "" + } + if s == `''` { + return "" + } + + if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' { + return s[1 : len(s)-2] + } + if len(s) >= 2 && s[0] == '\'' && s[len(s)-1] == '\'' { + return s[1 : len(s)-1] + } + + return s +} + +func atof(s string) float64 { + f, err := strconv.ParseFloat(s, 64) + if err != nil { + panic(err) + } + + return f +} + +// Atos - ASTree to string +// Typically using for debug +func Atos(node Node) string { + j, err := json.Marshal(node) + if err != nil { + panic(err) + } + var out bytes.Buffer + err = json.Indent(&out, j, "", "\t") + if err != nil { + panic(err) + } + var str string + str += fmt.Sprint("==== START OF AST tree ====\n") + str += out.String() + str += TypesTree(node) + str += fmt.Sprint("==== END OF AST tree ====\n") + return str +} + +// TypesTree - return tree of types for AST node +func TypesTree(node Node) (str string) { + str += fmt.Sprintf("\nTypes tree:\n") + str += typesTree(node, 0) + return str +} + +func typesTree(node Node, depth int) (str string) { + if node == (Node)(nil) { + return "" + } + for i := 0; i < depth; i++ { + str += "\t" + } + str += fmt.Sprintf("%T\n", node) + depth++ + if len(node.Children()) > 0 { + for _, n := range node.Children() { + str += typesTree(n, depth) + } + } + return str +} diff --git a/ast/va_arg_expr.go b/ast/va_arg_expr.go new file mode 100644 index 0000000..7cc07da --- /dev/null +++ b/ast/va_arg_expr.go @@ -0,0 +1,46 @@ +package ast + +// VAArgExpr is expression. +type VAArgExpr struct { + Addr Address + Pos Position + Type string + ChildNodes []Node +} + +func parseVAArgExpr(line string) *VAArgExpr { + groups := groupsFromRegex( + "<(?P.*)> '(?P.*)'", + line, + ) + + return &VAArgExpr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Type: groups["type"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *VAArgExpr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *VAArgExpr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *VAArgExpr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *VAArgExpr) Position() Position { + return n.Pos +} diff --git a/ast/va_arg_expr_test.go b/ast/va_arg_expr_test.go new file mode 100644 index 0000000..fc9881f --- /dev/null +++ b/ast/va_arg_expr_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestVAArgExpr(t *testing.T) { + nodes := map[string]Node{ + `0x7ff7d314bca8 'int *'`: &VAArgExpr{ + Addr: 0x7ff7d314bca8, + Pos: NewPositionFromString("col:6, col:31"), + Type: "int *", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/var_decl.go b/ast/var_decl.go new file mode 100644 index 0000000..29ec13b --- /dev/null +++ b/ast/var_decl.go @@ -0,0 +1,87 @@ +package ast + +import ( + "strings" +) + +// VarDecl is node represents a variable declaration. +type VarDecl struct { + Addr Address + Parent Address + Pos Position + Position2 string + Name string + Type string + Type2 string + IsExtern bool + IsUsed bool + IsCInit bool + IsReferenced bool + IsStatic bool + IsRegister bool + ChildNodes []Node +} + +func parseVarDecl(line string) *VarDecl { + groups := groupsFromRegex( + `(?:prev (?P0x[0-9a-f]+) )? + (?:parent (?P0x[0-9a-f]+) )? + <(?P.*)>(?P .+:\d+)? + (?P used)? + (?P referenced)? + (?P \w+)? + '(?P.+?)' + (?P:'.*?')? + (?P extern)? + (?P static)? + (?P cinit)? + (?P register)? + `, + line, + ) + + type2 := groups["type2"] + if type2 != "" { + type2 = type2[2 : len(type2)-1] + } + + return &VarDecl{ + Addr: ParseAddress(groups["address"]), + Parent: ParseAddress(groups["parent"]), + Pos: NewPositionFromString(groups["position"]), + Position2: strings.TrimSpace(groups["position2"]), + Name: strings.TrimSpace(groups["name"]), + Type: groups["type"], + Type2: type2, + IsExtern: len(groups["extern"]) > 0, + IsUsed: len(groups["used"]) > 0, + IsCInit: len(groups["cinit"]) > 0, + IsReferenced: len(groups["referenced"]) > 0, + IsStatic: len(groups["static"]) > 0, + IsRegister: len(groups["register"]) > 0, + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *VarDecl) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *VarDecl) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *VarDecl) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *VarDecl) Position() Position { + return n.Pos +} diff --git a/ast/var_decl_test.go b/ast/var_decl_test.go new file mode 100644 index 0000000..8d81114 --- /dev/null +++ b/ast/var_decl_test.go @@ -0,0 +1,172 @@ +package ast + +import ( + "testing" +) + +func TestVarDecl(t *testing.T) { + nodes := map[string]Node{ + `0x7fd5e90e5a00 col:17 'int'`: &VarDecl{ + Addr: 0x7fd5e90e5a00, + Pos: NewPositionFromString("col:14"), + Position2: "col:17", + Name: "", + Type: "int", + Type2: "", + IsExtern: false, + IsUsed: false, + IsCInit: false, + IsReferenced: false, + IsStatic: false, + IsRegister: false, + Parent: 0, + ChildNodes: []Node{}, + }, + `0x7fd5e90e9078 col:14 __stdinp 'FILE *' extern`: &VarDecl{ + Addr: 0x7fd5e90e9078, + Pos: NewPositionFromString("line:156:1, col:14"), + Position2: "col:14", + Name: "__stdinp", + Type: "FILE *", + Type2: "", + IsExtern: true, + IsUsed: false, + IsCInit: false, + IsReferenced: false, + IsStatic: false, + IsRegister: false, + Parent: 0, + ChildNodes: []Node{}, + }, + `0x7fd5e90ed630 col:47 __size 'size_t':'unsigned long'`: &VarDecl{ + Addr: 0x7fd5e90ed630, + Pos: NewPositionFromString("col:40, col:47"), + Position2: "col:47", + Name: "__size", + Type: "size_t", + Type2: "unsigned long", + IsExtern: false, + IsUsed: false, + IsCInit: false, + IsReferenced: false, + IsStatic: false, + IsRegister: false, + Parent: 0, + ChildNodes: []Node{}, + }, + `0x7fee35907a78 col:8 used c 'int'`: &VarDecl{ + Addr: 0x7fee35907a78, + Pos: NewPositionFromString("col:4, col:8"), + Position2: "col:8", + Name: "c", + Type: "int", + Type2: "", + IsExtern: false, + IsUsed: true, + IsCInit: false, + IsReferenced: false, + IsStatic: false, + IsRegister: false, + Parent: 0, + ChildNodes: []Node{}, + }, + `0x7fb0fd90ba30 tests/assert/assert.c:13:9 used b 'int *' cinit`: &VarDecl{ + Addr: 0x7fb0fd90ba30, + Pos: NewPositionFromString("col:3, /usr/include/sys/_types.h:52:33"), + Position2: "tests/assert/assert.c:13:9", + Name: "b", + Type: "int *", + Type2: "", + IsExtern: false, + IsUsed: true, + IsCInit: true, + IsReferenced: false, + IsStatic: false, + IsRegister: false, + Parent: 0, + ChildNodes: []Node{}, + }, + `0x7fb20308bd40 col:11 referenced a 'short'`: &VarDecl{ + Addr: 0x7fb20308bd40, + Pos: NewPositionFromString("col:5, col:11"), + Position2: "col:11", + Name: "a", + Type: "short", + Type2: "", + IsExtern: false, + IsUsed: false, + IsCInit: false, + IsReferenced: true, + IsStatic: false, + IsRegister: false, + Parent: 0, + ChildNodes: []Node{}, + }, + `0x55a040ddd798 line:66:27 used sqlite3azCompileOpt 'const char *const [2]' static cinit`: &VarDecl{ + Addr: 0x55a040ddd798, + Pos: NewPositionFromString("sqlite3.c:66:1, line:770:1"), + Position2: "line:66:27", + Name: "sqlite3azCompileOpt", + Type: "const char *const [2]", + Type2: "", + IsExtern: false, + IsUsed: true, + IsCInit: true, + IsReferenced: false, + IsStatic: true, + IsRegister: false, + Parent: 0, + ChildNodes: []Node{}, + }, + `0x55772c7774d0 col:27 used a 'unsigned char *' register`: &VarDecl{ + Addr: 0x55772c7774d0, + Pos: NewPositionFromString("col:3, col:27"), + Position2: "col:27", + Name: "a", + Type: "unsigned char *", + Type2: "", + IsExtern: false, + IsUsed: true, + IsCInit: false, + IsReferenced: false, + IsStatic: false, + IsRegister: true, + Parent: 0, + ChildNodes: []Node{}, + }, + `0x26fd180 col:13 used aExt 'extCoord':'extCoord' cinit`: &VarDecl{ + Addr: 0x26fd180, + Pos: NewPositionFromString("col:4, col:32"), + Position2: "col:13", + Name: "aExt", + Type: "extCoord", + Type2: "extCoord", + IsExtern: false, + IsUsed: true, + IsCInit: true, + IsReferenced: false, + IsStatic: false, + IsRegister: false, + Parent: 0, + ChildNodes: []Node{}, + }, + `0x7f985e0ffb10 parent 0x7f985e0246d0 col:20 used DEFAULT_MEM_ALLOCATOR 'cmark_mem':'struct cmark_mem' extern`: &VarDecl{ + Addr: 0x7f985e0ffb10, + Pos: NewPositionFromString("col:3, col:20"), + Position2: "col:20", + Name: "DEFAULT_MEM_ALLOCATOR", + Type: "cmark_mem", + Type2: "struct cmark_mem", + IsExtern: true, + IsUsed: true, + IsCInit: false, + IsReferenced: false, + IsStatic: false, + IsRegister: false, + Parent: 0x7f985e0246d0, + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/vector_type.go b/ast/vector_type.go new file mode 100644 index 0000000..8019cb7 --- /dev/null +++ b/ast/vector_type.go @@ -0,0 +1,51 @@ +package ast + +import ( + "github.com/elliotchance/c2go/util" +) + +// VectorType is vector type +type VectorType struct { + Addr Address + Type string + Length int + ChildNodes []Node +} + +func parseVectorType(line string) *VectorType { + groups := groupsFromRegex( + `'(?P.*)' + (?P[\d]+)`, + line, + ) + + return &VectorType{ + Addr: ParseAddress(groups["address"]), + Type: groups["type"], + Length: util.Atoi(groups["length"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *VectorType) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *VectorType) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *VectorType) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *VectorType) Position() Position { + return Position{} +} diff --git a/ast/verbatim_block_comment.go b/ast/verbatim_block_comment.go new file mode 100644 index 0000000..a7b41a1 --- /dev/null +++ b/ast/verbatim_block_comment.go @@ -0,0 +1,50 @@ +package ast + +// VerbatimBlockComment is a type of comment +type VerbatimBlockComment struct { + Addr Address + Pos Position + Name string + CloseName string + ChildNodes []Node +} + +func parseVerbatimBlockComment(line string) *VerbatimBlockComment { + groups := groupsFromRegex( + `<(?P.*)> + Name="(?P.*?)" + CloseName="(?P.*?)"`, + line, + ) + + return &VerbatimBlockComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Name: groups["name"], + CloseName: groups["close_name"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *VerbatimBlockComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *VerbatimBlockComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *VerbatimBlockComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *VerbatimBlockComment) Position() Position { + return n.Pos +} diff --git a/ast/verbatim_block_comment_test.go b/ast/verbatim_block_comment_test.go new file mode 100644 index 0000000..69106fa --- /dev/null +++ b/ast/verbatim_block_comment_test.go @@ -0,0 +1,19 @@ +package ast + +import ( + "testing" +) + +func TestVerbatimBlockComment(t *testing.T) { + nodes := map[string]Node{ + `0x107781dd0 Name="link" CloseName=""`: &VerbatimBlockComment{ + Addr: 0x107781dd0, + Pos: NewPositionFromString("col:34, col:39"), + Name: "link", + CloseName: "", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/verbatim_block_line_comment.go b/ast/verbatim_block_line_comment.go new file mode 100644 index 0000000..72474b6 --- /dev/null +++ b/ast/verbatim_block_line_comment.go @@ -0,0 +1,46 @@ +package ast + +// VerbatimBlockLineComment is a type of comment +type VerbatimBlockLineComment struct { + Addr Address + Pos Position + Text string + ChildNodes []Node +} + +func parseVerbatimBlockLineComment(line string) *VerbatimBlockLineComment { + groups := groupsFromRegex( + `<(?P.*)> Text="(?P.*?)"`, + line, + ) + + return &VerbatimBlockLineComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Text: groups["text"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *VerbatimBlockLineComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *VerbatimBlockLineComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *VerbatimBlockLineComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *VerbatimBlockLineComment) Position() Position { + return n.Pos +} diff --git a/ast/verbatim_block_line_comment_test.go b/ast/verbatim_block_line_comment_test.go new file mode 100644 index 0000000..152b843 --- /dev/null +++ b/ast/verbatim_block_line_comment_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestVerbatimBlockLineComment(t *testing.T) { + nodes := map[string]Node{ + `0x10f8e8e20 Text=" OSAtomicAdd32}"`: &VerbatimBlockLineComment{ + Addr: 0x10f8e8e20, + Pos: NewPositionFromString("col:39, col:54"), + Text: " OSAtomicAdd32}", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/verbatim_line_comment.go b/ast/verbatim_line_comment.go new file mode 100644 index 0000000..b7ebe4d --- /dev/null +++ b/ast/verbatim_line_comment.go @@ -0,0 +1,46 @@ +package ast + +// VerbatimLineComment is a type of comment +type VerbatimLineComment struct { + Addr Address + Pos Position + Text string + ChildNodes []Node +} + +func parseVerbatimLineComment(line string) *VerbatimLineComment { + groups := groupsFromRegex( + `<(?P.*)> Text="(?P.*)"`, + line, + ) + + return &VerbatimLineComment{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + Text: groups["text"], + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *VerbatimLineComment) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *VerbatimLineComment) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *VerbatimLineComment) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *VerbatimLineComment) Position() Position { + return n.Pos +} diff --git a/ast/verbatim_line_comment_test.go b/ast/verbatim_line_comment_test.go new file mode 100644 index 0000000..2dd0f3e --- /dev/null +++ b/ast/verbatim_line_comment_test.go @@ -0,0 +1,18 @@ +package ast + +import ( + "testing" +) + +func TestVerbatimLineComment(t *testing.T) { + nodes := map[string]Node{ + `0x108af4dd0 Text=" qos_class_self"`: &VerbatimLineComment{ + Addr: 0x108af4dd0, + Pos: NewPositionFromString("col:4, col:28"), + Text: " qos_class_self", + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/visibility_attr.go b/ast/visibility_attr.go new file mode 100644 index 0000000..0d91743 --- /dev/null +++ b/ast/visibility_attr.go @@ -0,0 +1,51 @@ +package ast + +// VisibilityAttr contains information for a VisibilityAttr AST line. +type VisibilityAttr struct { + Addr Address + Pos Position + ChildNodes []Node + IsDefault bool + IsInherited bool +} + +func parseVisibilityAttr(line string) *VisibilityAttr { + groups := groupsFromRegex( + `<(?P.*)> + (?P Inherited)? + (?P Default)? + `, + line, + ) + + return &VisibilityAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + IsDefault: len(groups["default"]) > 0, + IsInherited: len(groups["inherited"]) > 0, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *VisibilityAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *VisibilityAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *VisibilityAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *VisibilityAttr) Position() Position { + return n.Pos +} diff --git a/ast/visibility_attr_test.go b/ast/visibility_attr_test.go new file mode 100644 index 0000000..2d33a38 --- /dev/null +++ b/ast/visibility_attr_test.go @@ -0,0 +1,26 @@ +package ast + +import ( + "testing" +) + +func TestVisibilityAttr(t *testing.T) { + nodes := map[string]Node{ + `0x55c49d8dd1d8 Default`: &VisibilityAttr{ + Addr: 0x55c49d8dd1d8, + Pos: NewPositionFromString("col:16, col:36"), + ChildNodes: []Node{}, + IsInherited: false, + IsDefault: true, + }, + `0x7f8e7b00bb80 Inherited Default`: &VisibilityAttr{ + Addr: 0x7f8e7b00bb80, + Pos: NewPositionFromString("/cmark/src/cmark.h:497:16, col:36"), + ChildNodes: []Node{}, + IsInherited: true, + IsDefault: true, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/warn_unused_result_attr.go b/ast/warn_unused_result_attr.go new file mode 100644 index 0000000..8ea63b1 --- /dev/null +++ b/ast/warn_unused_result_attr.go @@ -0,0 +1,42 @@ +package ast + +// WarnUnusedResultAttr is a type of attribute that is optionally attached to a variable +// or struct field definition. +type WarnUnusedResultAttr struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseWarnUnusedResultAttr(line string) *WarnUnusedResultAttr { + groups := groupsFromRegex(`<(?P.*)>( warn_unused_result)?`, line) + + return &WarnUnusedResultAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *WarnUnusedResultAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *WarnUnusedResultAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *WarnUnusedResultAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *WarnUnusedResultAttr) Position() Position { + return n.Pos +} diff --git a/ast/warn_unused_result_attr_test.go b/ast/warn_unused_result_attr_test.go new file mode 100644 index 0000000..e155f12 --- /dev/null +++ b/ast/warn_unused_result_attr_test.go @@ -0,0 +1,22 @@ +package ast + +import ( + "testing" +) + +func TestWarnUnusedResultAttr(t *testing.T) { + nodes := map[string]Node{ + `0x7fa1d704d420 warn_unused_result`: &WarnUnusedResultAttr{ + Addr: 0x7fa1d704d420, + Pos: NewPositionFromString("col:60"), + ChildNodes: []Node{}, + }, + `0x1fac810 `: &WarnUnusedResultAttr{ + Addr: 0x1fac810, + Pos: NewPositionFromString("line:481:52"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/weak_attr.go b/ast/weak_attr.go new file mode 100644 index 0000000..d1c8f74 --- /dev/null +++ b/ast/weak_attr.go @@ -0,0 +1,43 @@ +package ast + +// WeakAttr for the WeakAttr node +type WeakAttr struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseWeakAttr(line string) *WeakAttr { + groups := groupsFromRegex( + `<(?P.*)>`, + line, + ) + + return &WeakAttr{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild method to implements Node interface +func (n *WeakAttr) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *WeakAttr) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *WeakAttr) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *WeakAttr) Position() Position { + return n.Pos +} diff --git a/ast/weak_attr_test.go b/ast/weak_attr_test.go new file mode 100644 index 0000000..be33c9e --- /dev/null +++ b/ast/weak_attr_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestWeakAttr(t *testing.T) { + nodes := map[string]Node{ + `0x56069ece5110 `: &WeakAttr{ + Addr: 0x56069ece5110, + Pos: NewPositionFromString("line:736:22"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/ast/while_stmt.go b/ast/while_stmt.go new file mode 100644 index 0000000..0adf0fe --- /dev/null +++ b/ast/while_stmt.go @@ -0,0 +1,44 @@ +package ast + +// WhileStmt is node represent 'while' +type WhileStmt struct { + Addr Address + Pos Position + ChildNodes []Node +} + +func parseWhileStmt(line string) *WhileStmt { + groups := groupsFromRegex( + "<(?P.*)>", + line, + ) + + return &WhileStmt{ + Addr: ParseAddress(groups["address"]), + Pos: NewPositionFromString(groups["position"]), + ChildNodes: []Node{}, + } +} + +// AddChild adds a new child node. Child nodes can then be accessed with the +// Children attribute. +func (n *WhileStmt) AddChild(node Node) { + n.ChildNodes = append(n.ChildNodes, node) +} + +// Address returns the numeric address of the node. See the documentation for +// the Address type for more information. +func (n *WhileStmt) Address() Address { + return n.Addr +} + +// Children returns the child nodes. If this node does not have any children or +// this node does not support children it will always return an empty slice. +func (n *WhileStmt) Children() []Node { + return n.ChildNodes +} + +// Position returns the position in the original source code. +func (n *WhileStmt) Position() Position { + return n.Pos +} diff --git a/ast/while_stmt_test.go b/ast/while_stmt_test.go new file mode 100644 index 0000000..005ea3f --- /dev/null +++ b/ast/while_stmt_test.go @@ -0,0 +1,17 @@ +package ast + +import ( + "testing" +) + +func TestWhileStmt(t *testing.T) { + nodes := map[string]Node{ + `0x7fa1478273a0 `: &WhileStmt{ + Addr: 0x7fa1478273a0, + Pos: NewPositionFromString("line:7:4, line:11:4"), + ChildNodes: []Node{}, + }, + } + + runNodeTests(t, nodes) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..8d8d2ad --- /dev/null +++ b/main.go @@ -0,0 +1,331 @@ +package main + +import ( + "flag" + "fmt" + "os" + "os/exec" + "runtime" + "strings" + + "gitlab.wow.st/gmp/clast/ast" + "gitlab.wow.st/gmp/clast/wrap" +) + +type ProgramArgs struct { + verbose bool + ast bool + inputFiles []string + clangFlags []string + outputFile string + packageName string + + // A private option to output the Go as a *_test.go file. + outputAsTest bool +} + +// DefaultProgramArgs default value of ProgramArgs +func DefaultProgramArgs() ProgramArgs { + return ProgramArgs{ + verbose: false, + ast: false, + packageName: "main", + clangFlags: []string{}, + outputAsTest: false, + } +} + +func readAST(data []byte) []string { + return strings.Split(string(data), "\n") +} + +type treeNode struct { + indent int + node ast.Node +} + +func convertLinesToNodes(lines []string) []treeNode { + nodes := make([]treeNode, len(lines)) + var counter int + for _, line := range lines { + if strings.TrimSpace(line) == "" { + continue + } + + // It is tempting to discard null AST nodes, but these may + // have semantic importance: for example, they represent omitted + // for-loop conditions, as in for(;;). + line = strings.Replace(line, "<<>>", "NullStmt", 1) + trimmed := strings.TrimLeft(line, "|\\- `") + node := ast.Parse(trimmed) + indentLevel := (len(line) - len(trimmed)) / 2 + nodes[counter] = treeNode{indentLevel, node} + counter++ + } + nodes = nodes[0:counter] + + return nodes +} + +func convertLinesToNodesParallel(lines []string) []treeNode { + // function f separate full list on 2 parts and + // then each part can recursive run function f + var f func([]string, int) []treeNode + + f = func(lines []string, deep int) []treeNode { + deep = deep - 2 + part := len(lines) / 2 + + var tr1 = make(chan []treeNode) + var tr2 = make(chan []treeNode) + + go func(lines []string, deep int) { + if deep <= 0 || len(lines) < deep { + tr1 <- convertLinesToNodes(lines) + return + } + tr1 <- f(lines, deep) + }(lines[0:part], deep) + + go func(lines []string, deep int) { + if deep <= 0 || len(lines) < deep { + tr2 <- convertLinesToNodes(lines) + return + } + tr2 <- f(lines, deep) + }(lines[part:], deep) + + defer close(tr1) + defer close(tr2) + + return append(<-tr1, <-tr2...) + } + + // Parameter of deep - can be any, but effective to use + // same amount of CPU + return f(lines, runtime.NumCPU()) +} + +// buildTree converts an array of nodes, each prefixed with a depth into a tree. +func buildTree(nodes []treeNode, depth int) []ast.Node { + if len(nodes) == 0 { + return []ast.Node{} + } + + // Split the list into sections, treat each section as a tree with its own + // root. + sections := [][]treeNode{} + for _, node := range nodes { + if node.indent == depth { + sections = append(sections, []treeNode{node}) + } else { + sections[len(sections)-1] = append(sections[len(sections)-1], node) + } + } + + results := []ast.Node{} + for _, section := range sections { + slice := []treeNode{} + for _, n := range section { + if n.indent > depth { + slice = append(slice, n) + } + } + + children := buildTree(slice, depth+1) + for _, child := range children { + section[0].node.AddChild(child) + } + results = append(results, section[0].node) + } + + return results +} + +// Start begins transpiling an input file. +func Start(args ProgramArgs) (err error) { + if args.verbose { + fmt.Println("Start tanspiling ...") + } + + if os.Getenv("GOPATH") == "" { + return fmt.Errorf("The $GOPATH must be set") + } + + // 1. Compile it first (checking for errors) + for _, in := range args.inputFiles { + _, err := os.Stat(in) + if err != nil { + return fmt.Errorf("Input file %s is not found", in) + } + } + + // 2. Preprocess NOT DONE + + // 3. Generate JSON from AST + if args.verbose { + fmt.Println("Running clang for AST tree...") + } + cargs := []string{"-xobjective-c", "-Xclang", "-ast-dump", + "-fsyntax-only","-fno-color-diagnostics"} + cargs = append(cargs,args.inputFiles...) + astPP, err := exec.Command("clang",cargs...).Output() + if err != nil { + // If clang fails it still prints out the AST, so we have to run it + // again to get the real error. + errBody, _ := exec.Command("clang", cargs...).CombinedOutput() + + panic("clang failed: " + err.Error() + ":\n\n" + string(errBody)) + } + + if args.verbose { + fmt.Println("Reading clang AST tree...") + } + lines := readAST(astPP) + if args.ast { + for _, l := range lines { + fmt.Println(l) + } + fmt.Println() + + return nil + } + + // Converting to nodes + if args.verbose { + fmt.Println("Converting to nodes...") + } + nodes := convertLinesToNodesParallel(lines) + + // build tree + if args.verbose { + fmt.Println("Building tree...") + } + tree := buildTree(nodes, 0) + unit := tree[0] + w := wrap.NewWrapper() + for _, n := range(unit.Children()) { + switch x := n.(type) { + case *ast.ObjCInterfaceDecl: + if x.Name == "CBPeripheral" { + w.Wrap(x) + } + } + } + return nil +} + +type inputDataFlags []string + +func (i *inputDataFlags) String() (s string) { + for pos, item := range *i { + s += fmt.Sprintf("Flag %d. %s\n", pos, item) + } + return +} + +func (i *inputDataFlags) Set(value string) error { + *i = append(*i, value) + return nil +} + +var clangFlags inputDataFlags + +func init() { + transpileCommand.Var(&clangFlags, "clang-flag", "Pass arguments to clang. You may provide multiple -clang-flag items.") + astCommand.Var(&clangFlags, "clang-flag", "Pass arguments to clang. You may provide multiple -clang-flag items.") +} + +var ( + versionFlag = flag.Bool("v", false, "print the version and exit") + transpileCommand = flag.NewFlagSet("transpile", flag.ContinueOnError) + verboseFlag = transpileCommand.Bool("V", false, "print progress as comments") + outputFlag = transpileCommand.String("o", "", "output Go generated code to the specified file") + packageFlag = transpileCommand.String("p", "main", "set the name of the generated package") + transpileHelpFlag = transpileCommand.Bool("h", false, "print help information") + astCommand = flag.NewFlagSet("ast", flag.ContinueOnError) + astHelpFlag = astCommand.Bool("h", false, "print help information") +) + +func main() { + code := runCommand() + if code != 0 { + os.Exit(code) + } +} + +func runCommand() int { + + flag.Usage = func() { + usage := "Usage: %s [-v] [] [] file1.c ...\n\n" + usage += "Commands:\n" + usage += " transpile\ttranspile an input C source file or files to Go\n" + usage += " ast\t\tprint AST before translated Go code\n\n" + + usage += "Flags:\n" + fmt.Printf(usage, os.Args[0]) + flag.PrintDefaults() + } + + flag.Parse() + + if *versionFlag { + // Simply print out the version and exit. + fmt.Println("version") + return 0 + } + + if flag.NArg() < 1 { + flag.Usage() + return 1 + } + + args := DefaultProgramArgs() + + switch os.Args[1] { + case "ast": + err := astCommand.Parse(os.Args[2:]) + if err != nil { + fmt.Printf("ast command cannot parse: %v", err) + return 1 + } + + if *astHelpFlag || astCommand.NArg() == 0 { + fmt.Printf("Usage: %s ast file.c\n", os.Args[0]) + astCommand.PrintDefaults() + return 1 + } + + args.ast = true + args.inputFiles = astCommand.Args() + args.clangFlags = clangFlags + case "transpile": + err := transpileCommand.Parse(os.Args[2:]) + if err != nil { + fmt.Printf("transpile command cannot parse: %v", err) + return 1 + } + + if *transpileHelpFlag || transpileCommand.NArg() == 0 { + fmt.Printf("Usage: %s transpile [-V] [-o file.go] [-p package] file1.c ...\n", os.Args[0]) + transpileCommand.PrintDefaults() + return 1 + } + + args.inputFiles = transpileCommand.Args() + args.outputFile = *outputFlag + args.packageName = *packageFlag + args.verbose = *verboseFlag + args.clangFlags = clangFlags + default: + flag.Usage() + return 1 + } + + if err := Start(args); err != nil { + fmt.Printf("Error: %v\n", err) + return 1 + } + + return 0 +} diff --git a/objc/main.m b/objc/main.m new file mode 100644 index 0000000..21c4472 --- /dev/null +++ b/objc/main.m @@ -0,0 +1,8 @@ +#import + +int +main(int argc, char* argv[]) { + CBCentralManager *m; + return 0; +} + diff --git a/wrap/main.go b/wrap/main.go new file mode 100644 index 0000000..5297d21 --- /dev/null +++ b/wrap/main.go @@ -0,0 +1,29 @@ +package wrap + +import ( + "fmt" + "reflect" + + "gitlab.wow.st/gmp/clast/ast" +) + +type Wrapper struct { +} + +func NewWrapper() *Wrapper { + return &Wrapper{} +} + +func (w *Wrapper) Wrap(n *ast.ObjCInterfaceDecl) { + fmt.Println("//generated by gitlab.wow.st/gmp/clast") + for _,c := range n.Children() { + switch x := c.(type) { + case *ast.Unknown: + fmt.Printf("%s: %s\n",x.Name,x.Content) + case *ast.ObjCMethodDecl: + fmt.Printf("*ast.ObjCMethodDecl: %s (%s %s)\n",x.Name,x.Type, x.Attr) + default: + fmt.Println(reflect.TypeOf(x)) + } + } +}