pax_global_header00006660000000000000000000000064141060175320014511gustar00rootroot0000000000000052 comment=5420ffae5e7929c73af40b0170df50b578d3d38f c2go-0.26.10/000077500000000000000000000000001410601753200125115ustar00rootroot00000000000000c2go-0.26.10/.codeclimate.yml000066400000000000000000000004121410601753200155600ustar00rootroot00000000000000engines: # The FIXME engine will be disabled for the timebeing because there will be a # lot of these initially. fixme: enabled: true gofmt: enabled: true golint: enabled: true govet: enabled: true ratings: paths: - "**.go" c2go-0.26.10/.gitattributes000066400000000000000000000000321410601753200153770ustar00rootroot00000000000000tests/* linguist-vendored c2go-0.26.10/.gitignore000066400000000000000000000001671410601753200145050ustar00rootroot00000000000000.DS_Store /pp.c /out.go /a.out /pp.json /out /.idea /build /bin /coverage.txt /c2go /.vscode *.coverprofile tests/*.go c2go-0.26.10/.snapshots/000077500000000000000000000000001410601753200146115ustar00rootroot00000000000000c2go-0.26.10/.snapshots/c2go-TestCLI-func1-AstHelpFlag000066400000000000000000000002431410601753200217740ustar00rootroot00000000000000(*bytes.Buffer)(Usage: test ast file.c -clang-flag value Pass arguments to clang. You may provide multiple -clang-flag items. -h print help information ) c2go-0.26.10/.snapshots/c2go-TestCLI-func1-AstNoFilesHelp000066400000000000000000000002431410601753200224620ustar00rootroot00000000000000(*bytes.Buffer)(Usage: test ast file.c -clang-flag value Pass arguments to clang. You may provide multiple -clang-flag items. -h print help information ) c2go-0.26.10/.snapshots/c2go-TestCLI-func1-TranspileHelpFlag000066400000000000000000000005651410601753200232150ustar00rootroot00000000000000(*bytes.Buffer)(Usage: test transpile [-V] [-o file.go] [-p package] file1.c ... -V print progress as comments -clang-flag value Pass arguments to clang. You may provide multiple -clang-flag items. -h print help information -o string output Go generated code to the specified file -p string set the name of the generated package (default "main") ) c2go-0.26.10/.snapshots/c2go-TestCLI-func1-TranspileNoFilesHelp000066400000000000000000000005651410601753200237030ustar00rootroot00000000000000(*bytes.Buffer)(Usage: test transpile [-V] [-o file.go] [-p package] file1.c ... -V print progress as comments -clang-flag value Pass arguments to clang. You may provide multiple -clang-flag items. -h print help information -o string output Go generated code to the specified file -p string set the name of the generated package (default "main") ) c2go-0.26.10/.travis.yml000066400000000000000000000041241410601753200146230ustar00rootroot00000000000000language: go go: - "1.9.x" os: - linux - osx env: global: secure: "p/4P6/KQKnkUmTQPUkkuu/Q9n4KR9tno5i6gBf9yJ/SbBRg1YTM5G5QvvZUasOAOeb8sxQaoJqd+H6Jmnj3sgB/zBFrAId+S8IMckuUMPLGvt928MXA+R1DdRDr9arHGKodyaF6VUJkQU78IQusv71FDvV2bdesMJPNc27l3WbEJPEoPGpQMiM6pgZgYFEnpRHTgi3Fmp5FN9jR+evQpPOwvsAVfNuLH2kZ3prk7XDpP2Nx0SmdwVzSKiKFW8XyiM6aHmjWLOOIDbmIynD1Hl2iUTEhbzubIPgBmYt3AbgYL4WzmnnZEfKMFmVGjHmdNIiW1EndI4iLjCpqdTWqOLY7kge8DW+/eURb0WsIAJJsllc/D6P9l2SU1v9PJROdY2dLI5oO06PSvFgXgpyCz0IG1ARYw2JF9JxG1kkNtdcPindn3mlPTcfwHUh41y7mZEYBD22NMl9AyWE1Igqgx2TEYZf+TcyUpV2pLxY7QwcCrga77iCiSrzylKLvrgABaU/zgQXEUe2Oymv4LvgtiwMBJl6x+80yVEMdIMHb10IShThzEgcmMDd1rNDt8k48A3GUVaFi4xu4i3Zoiq2OGQLNOKmejWpNYYHP7iD6gTqRwV5h9t+iTobbxs1WkJfh5VMHKaLN1qQmEz3Nzr08zZ8rkAJ9X3Xf588HhZKVvVsQ=" matrix: - SCRIPT=test CLANG=3.9 matrix: include: - env: SCRIPT=test CLANG=3.4 os: linux - env: SCRIPT=test CLANG=3.5 os: linux - env: SCRIPT=test CLANG=3.6 os: linux - env: SCRIPT=test CLANG=3.7 os: linux - env: SCRIPT=test CLANG=3.8 os: linux - env: SCRIPT=test CLANG=5.0 os: linux - env: SCRIPT=lint CLANG=3.9 os: linux before_install: - | if [ "$TRAVIS_OS_NAME" = "linux" ]; then wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y sudo apt-add-repository "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-$CLANG main" sudo apt-get update sudo apt-cache search clang sudo apt-get install -f -y --force-yes clang-$CLANG lldb-$CLANG fi # gocovmerge is used to merge all the separate unit/integration test coverage # profiles. - go get -u -v github.com/wadey/gocovmerge # install gometalinter - go get -u github.com/alecthomas/gometalinter - gometalinter --install script: - . ./travis/$SCRIPT.sh after_success: - include_cov=coverage.txt bash <(curl -s https://codecov.io/bash) after_failure: # Print out the failures (removing a lot of the noise). - cat /tmp/out.txt | grep -v -- "--- PASS" | grep -v -- "=== RUN" c2go-0.26.10/CODE_OF_CONDUCT.md000066400000000000000000000062231410601753200153130ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at elliotchance@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ c2go-0.26.10/LICENSE000066400000000000000000000021331410601753200135150ustar00rootroot00000000000000MIT License Copyright (c) 2017 Elliot Chance, Izyumov Konstantin and Christophe Kamphaus. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. c2go-0.26.10/README.md000066400000000000000000000120461410601753200137730ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/elliotchance/c2go.svg?branch=master)](https://travis-ci.org/elliotchance/c2go) [![GitHub version](https://badge.fury.io/gh/elliotchance%2Fc2go.svg)](https://badge.fury.io/gh/elliotchance%2Fc2go) [![Go Report Card](https://goreportcard.com/badge/github.com/elliotchance/c2go)](https://goreportcard.com/report/github.com/elliotchance/c2go) [![codecov](https://codecov.io/gh/elliotchance/c2go/branch/master/graph/badge.svg)](https://codecov.io/gh/elliotchance/c2go) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/elliotchance/c2go/master/LICENSE) [![Join the chat at https://gitter.im/c2goproject](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/c2goproject?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Twitter](https://img.shields.io/twitter/url/https/github.com/elliotchance/c2go.svg?style=social)](https://twitter.com/intent/tweet?text=Wow:&url=%5Bobject%20Object%5D) [![GoDoc](https://godoc.org/github.com/elliotchance/c2go?status.svg)](https://godoc.org/github.com/elliotchance/c2go) A tool for converting C to Go. The goals of this project are: 1. To create a generic tool that can convert C to Go. 2. To be cross platform (linux and mac) and work against as many clang versions as possible (the clang AST API is not stable). 3. To be a repeatable and predictable tool (rather than doing most of the work and you have to clean up the output to get it working.) 4. To deliver quick and small version increments. 5. The ultimate milestone is to be able to compile the [SQLite3 source code](https://sqlite.org/download.html) and have it working without modification. This will be the 1.0.0 release. # Installation `c2go` requires Go 1.9 or newer. ```bash go get -u github.com/elliotchance/c2go ``` # Usage ```bash c2go transpile myfile.c ``` The `c2go` program processes a single C file and outputs the translated code in Go. Let's use an included example, [prime.c](https://github.com/elliotchance/c2go/blob/master/examples/prime.c): ```c #include int main() { int n, c; printf("Enter a number\n"); scanf("%d", &n); if ( n == 2 ) printf("Prime number.\n"); else { for ( c = 2 ; c <= n - 1 ; c++ ) { if ( n % c == 0 ) break; } if ( c != n ) printf("Not prime.\n"); else printf("Prime number.\n"); } return 0; } ``` ```bash c2go transpile prime.c go run prime.go ``` ``` Enter a number 23 Prime number. ``` `prime.go` looks like: ```go package main import "unsafe" import "github.com/elliotchance/c2go/noarch" // ... lots of system types in Go removed for brevity. var stdin *noarch.File var stdout *noarch.File var stderr *noarch.File func main() { __init() var n int var c int noarch.Printf([]byte("Enter a number\n\x00")) noarch.Scanf([]byte("%d\x00"), (*[1]int)(unsafe.Pointer(&n))[:]) if n == 2 { noarch.Printf([]byte("Prime number.\n\x00")) } else { for c = 2; c <= n-1; func() int { c += 1 return c }() { if n%c == 0 { break } } if c != n { noarch.Printf([]byte("Not prime.\n\x00")) } else { noarch.Printf([]byte("Prime number.\n\x00")) } } return } func __init() { stdin = noarch.Stdin stdout = noarch.Stdout stderr = noarch.Stderr } ``` # How It Works This is the process: 1. The C code is preprocessed with clang. This generates a larger file (`pp.c`), but removes all the platform-specific directives and macros. 2. `pp.c` is parsed with the clang AST and dumps it in a colourful text format that [looks like this](http://ehsanakhgari.org/wp-content/uploads/2015/12/Screen-Shot-2015-12-03-at-5.02.38-PM.png). Apart from just parsing the C and dumping an AST, the AST contains all of the resolved information that a compiler would need (such as data types). This means that the code must compile successfully under clang for the AST to also be usable. 3. Since we have all the types in the AST it's just a matter of traversing the tree in a semi-intelligent way and producing Go. Easy, right!? # Testing By default only unit tests are run with `go test`. You can also include the integration tests: ```bash go test -tags=integration ./... ``` Integration tests in the form of complete C programs that can be found in the [tests](https://github.com/elliotchance/c2go/tree/master/tests) directory. Integration tests work like this: 1. Clang compiles the C to a binary as normal. 2. c2go converts the C file to Go. 3. The Go is built to produce another binary. 4. Both binaries are executed and the output is compared. All C files will contain some output so the results can be verified. # Contributing Contributing is done with pull requests. There is no help that is too small! :) If you're looking for where to start I can suggest [finding a simple C program](http://www.programmingsimplified.com/c-program-examples) (like the other examples) that does not successfully translate into Go. Or, if you don't want to do that you can submit it as an issue so that it can be picked up by someone else. c2go-0.26.10/ast/000077500000000000000000000000001410601753200133005ustar00rootroot00000000000000c2go-0.26.10/ast/aligned_attr.go000066400000000000000000000023771410601753200162750ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/aligned_attr_test.go000066400000000000000000000007531410601753200173300ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/alloc_size_attr.go000066400000000000000000000027751410601753200170200ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/alloc_size_attr_test.go000066400000000000000000000011471410601753200200470ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/always_inline_attr.go000066400000000000000000000023511410601753200175200ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/always_inline_attr_test.go000066400000000000000000000005441410601753200205610ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/array_filler.go000066400000000000000000000017051410601753200163050ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/array_filler_test.go000066400000000000000000000005311410601753200173400ustar00rootroot00000000000000package 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))) } } c2go-0.26.10/ast/array_subscript_expr.go000066400000000000000000000025641410601753200201100ustar00rootroot00000000000000package ast // ArraySubscriptExpr is expression. type ArraySubscriptExpr struct { Addr Address Pos Position Type string Type2 string IsLvalue bool ChildNodes []Node } func parseArraySubscriptExpr(line string) *ArraySubscriptExpr { groups := groupsFromRegex( `<(?P.*)> '(?P.*?)'(:'(?P.*?)')? (?P lvalue)?`, line, ) return &ArraySubscriptExpr{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), Type: groups["type"], Type2: groups["type2"], IsLvalue: len(groups["lvalue"]) > 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 } c2go-0.26.10/ast/array_subscript_expr_test.go000066400000000000000000000016351410601753200211450ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/asm_label_attr.go000066400000000000000000000026621410601753200166060ustar00rootroot00000000000000package ast // AsmLabelAttr is a type of attribute for assembler label type AsmLabelAttr struct { Addr Address Pos Position Inherited bool FunctionName string ChildNodes []Node IsLiteralLabel bool } func parseAsmLabelAttr(line string) *AsmLabelAttr { groups := groupsFromRegex( `<(?P.*)> (?P Inherited)? "(?P.+)" (?P IsLiteralLabel)?`, line, ) return &AsmLabelAttr{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), Inherited: len(groups["inherited"]) > 0, FunctionName: groups["function"], ChildNodes: []Node{}, IsLiteralLabel: len(groups["literal"]) > 0, } } // 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 } c2go-0.26.10/ast/asm_label_attr_test.go000066400000000000000000000020171410601753200176370ustar00rootroot00000000000000package 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{}, IsLiteralLabel: false, }, `0x7fd55a169318 Inherited "_popen"`: &AsmLabelAttr{ Addr: 0x7fd55a169318, Pos: NewPositionFromString("/usr/include/stdio.h:325:47"), Inherited: true, FunctionName: "_popen", ChildNodes: []Node{}, IsLiteralLabel: false, }, `0x559fea32f5f0 "__isoc99_fscanf" IsLiteralLabel`: &AsmLabelAttr{ Addr: 0x559fea32f5f0, Pos: NewPositionFromString("line:407:94"), Inherited: false, FunctionName: "__isoc99_fscanf", ChildNodes: []Node{}, IsLiteralLabel: true, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/ast.go000066400000000000000000000213751410601753200144260ustar00rootroot00000000000000// 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. // // TODO: remove this special case (including the ArrayFiller AST node)? Never // versions of Clang (9.0+) use array_filler as a prefix of other nodes (e.g. // ImplicitValueInitExpr). if line == "array filler" { return parseArrayFiller(line) } // In Clang 9.0, array_filler may be used as a prefix to a // ImplicitValueInitExpr, when implicitly initializing one or more elements of // an array. // // Example: // // array_filler: ImplicitValueInitExpr 0x5652b1a1faf8 <> 'int' const arrayFillerPrefix = "array_filler: " isArrayFiller := false if strings.HasPrefix(line, arrayFillerPrefix) { line = strings.TrimPrefix(line, arrayFillerPrefix) isArrayFiller = true } parts := strings.SplitN(line, " ", 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 "BreakStmt": return parseBreakStmt(line) case "BuiltinType": return parseBuiltinType(line) case "C11NoReturnAttr": return parseC11NoReturnAttr(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 "ConstantExpr": return parseConstantExpr(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 "FunctionNoProtoType": return parseFunctionNoProtoType(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": n := parseImplicitValueInitExpr(line) n.IsArrayFiller = isArrayFiller return n 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 "NoAliasAttr": return parseNoAliasAttr(line) case "NoInlineAttr": return parseNoInlineAttr(line) case "NoThrowAttr": return parseNoThrowAttr(line) case "NonNullAttr": return parseNonNullAttr(line) case "NotTailCalledAttr": return parseNotTailCalledAttr(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 "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 default: panic("unknown node type: '" + fullline + "'") } } 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 } c2go-0.26.10/ast/ast_test.go000066400000000000000000000027661410601753200154700ustar00rootroot00000000000000package 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) } } } c2go-0.26.10/ast/attributed_type.go000066400000000000000000000022061410601753200170370ustar00rootroot00000000000000package ast // AttributedType is an attribute type type AttributedType struct { Addr Address Type string Sugar bool ChildNodes []Node } func parseAttributedType(line string) *AttributedType { groups := groupsFromRegex(`'(?P.*?)' sugar`, line) return &AttributedType{ 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 *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{} } c2go-0.26.10/ast/attributed_type_test.go000066400000000000000000000005261410601753200201010ustar00rootroot00000000000000package ast import ( "testing" ) func TestAttributedType(t *testing.T) { nodes := map[string]Node{ `0x2b6c359e30 'int (void) __attribute__((cdecl))' sugar`: &AttributedType{ Addr: 0x2b6c359e30, Type: "int (void) __attribute__((cdecl))", Sugar: true, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/availability_attr.go000066400000000000000000000037551410601753200173450ustar00rootroot00000000000000package ast import ( "github.com/elliotchance/c2go/util" ) // 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 float64 Unknown2 int 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: atof(groups["unknown1"]), Unknown2: util.Atoi(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 } c2go-0.26.10/ast/availability_attr_test.go000066400000000000000000000071671410601753200204050ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/binary_operator.go000066400000000000000000000025261410601753200170330ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/binary_operator_test.go000066400000000000000000000011711410601753200200650ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/block_command_comment.go000066400000000000000000000023601410601753200201420ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/block_command_comment_test.go000066400000000000000000000005471410601753200212060ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/break_stmt.go000066400000000000000000000021261410601753200157630ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/break_stmt_test.go000066400000000000000000000004461410601753200170250ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/builtin_type.go000066400000000000000000000021031410601753200163320ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/builtin_type_test.go000066400000000000000000000006401410601753200173750ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/c11_no_return_attr.go000066400000000000000000000023151410601753200173410ustar00rootroot00000000000000package ast // C11NoReturnAttr is a type of attribute that is optionally attached to a function // with return type void. type C11NoReturnAttr struct { Addr Address Pos Position ChildNodes []Node } func parseC11NoReturnAttr(line string) *C11NoReturnAttr { groups := groupsFromRegex( "<(?P.*)>", line, ) return &C11NoReturnAttr{ 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 *C11NoReturnAttr) 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 *C11NoReturnAttr) 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 *C11NoReturnAttr) Children() []Node { return n.ChildNodes } // Position returns the position in the original source code. func (n *C11NoReturnAttr) Position() Position { return n.Pos } c2go-0.26.10/ast/c11_no_return_attr_test.go000066400000000000000000000004401410601753200203750ustar00rootroot00000000000000package ast import ( "testing" ) func TestC11NoReturnAttr(t *testing.T) { nodes := map[string]Node{ `0x55a5fc736cf0 `: &C11NoReturnAttr{ Addr: 0x55a5fc736cf0, Pos: NewPositionFromString("col:1"), ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/c_style_cast_expr.go000066400000000000000000000030071410601753200173410ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/c_style_cast_expr_test.go000066400000000000000000000012151410601753200203770ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/call_expr.go000066400000000000000000000022031410601753200155750ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/call_expr_test.go000066400000000000000000000010051410601753200166330ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/case_stmt.go000066400000000000000000000021041410601753200156060ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/case_stmt_test.go000066400000000000000000000004621410601753200166520ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/character_literal.go000066400000000000000000000171511410601753200173040ustar00rootroot00000000000000package ast import ( "errors" "fmt" "github.com/elliotchance/c2go/cc" "github.com/elliotchance/c2go/util" "reflect" ) // 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 } // CharacterLiteralError represents one instance of an error where the exact // character value of a CharacterLiteral could not be determined from the // original source. See RepairCharacterLiteralsFromSource for a full explanation. type CharacterLiteralError struct { Node *CharacterLiteral Err error } // RepairCharacterLiteralsFromSource finds the exact values of character literals // by reading their values directly from the preprocessed source. // // This is to solve issue #663, sometime clang serializes hex encoded character literals // as a weird number, e.g. '\xa0' => 4294967200 // // The only solution is to read the original character literal from the source // code. We can do this by using the positional information on the node. // // If the character literal cannot be resolved for any reason the original value // will remain. This function will return all errors encountered. func RepairCharacterLiteralsFromSource(rootNode Node, preprocessedFile string) []CharacterLiteralError { errs := []CharacterLiteralError{} characterLiteralNodes := GetAllNodesOfType(rootNode, reflect.TypeOf((*CharacterLiteral)(nil))) for _, node := range characterLiteralNodes { cNode := node.(*CharacterLiteral) pos := node.Position() var ( err error lastLine = pos.LineEnd i int ) if lastLine == 0 { lastLine = pos.Line } for line := pos.Line; line <= lastLine; line++ { i, err = parseCharacterLiteralFromPosition(preprocessedFile, pos, line) if err == nil { cNode.Value = i break } } if err != nil { errs = append(errs, CharacterLiteralError{ Node: cNode, Err: err, }) } } return errs } func parseCharacterLiteralFromPosition(preprocessedFile string, pos Position, lineNbr int) (ret int, err error) { // Use the node position to retrieve the original line from the // preprocessed source. line, err := cc.GetLineFromPreprocessedFile(preprocessedFile, pos.File, lineNbr) // 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 { return 0, err } // Extract the exact value from the line. if pos.Column-1 >= len(line) { return 0, errors.New("cannot get exact value") } literal := line[pos.Column-1:] if ret, err = parseCharacterLiteralFromSource(literal); err == nil { return ret, nil } return 0, fmt.Errorf("cannot parse character literal: %v from %s", err, literal) } func parseCharacterLiteralFromSource(literal string) (ret int, err error) { runes := []rune(literal) if len(runes) < 1 { return 0, fmt.Errorf("character literal to short") } // Consume leading ' switch runes[0] { case '\'': runes = runes[1:] case 'u', 'U', 'L': if len(runes) < 2 { return 0, fmt.Errorf("character literal to short") } if runes[1] == '\'' { runes = runes[2:] } else if runes[1] == '8' { if len(runes) < 3 { return 0, fmt.Errorf("character literal to short") } else if runes[2] != '\'' { return 0, fmt.Errorf("illegal character '%s' at index 2", string(runes[2])) } runes = runes[3:] } else { return 0, fmt.Errorf("illegal character '%s' at index 1", string(runes[1])) } default: return 0, fmt.Errorf("illegal character '%s' at index 0", string(runes[0])) } // we need place for at least 1 character and ' if len(runes) < 1 { return 0, fmt.Errorf("unexpected end of character literal") } // decode character literal var r rune var i int switch runes[0] { case '\'': return 0, fmt.Errorf("empty character literal") case '\\': if len(runes) < 2 { return 0, fmt.Errorf("unexpected end of character literal") } r, i, err = decodeEscapeSequence(runes) default: r = runes[0] i = 1 } if err != nil { return 0, err } if len(runes) <= i { return 0, fmt.Errorf("unexpected end of character literal") } if runes[i] != '\'' { return 0, fmt.Errorf("does not support multi-character literals") } return int(r), nil } // escape-sequence {simple-sequence}|{octal-escape-sequence}|{hexadecimal-escape-sequence}|{universal-character-name} // simple-sequence \\['\x22?\\abfnrtv] // octal-escape-sequence \\{octal-digit}{octal-digit}?{octal-digit}? // hexadecimal-escape-sequence \\x{hexadecimal-digit}+ func decodeEscapeSequence(runes []rune) (rune, int, error) { if runes[0] != '\\' { panic("internal error") } r := runes[1] switch r { case '\'', '"', '?', '\\': return r, 2, nil case 'a': return 7, 2, nil case 'b': return 8, 2, nil case 'f': return 12, 2, nil case 'n': return 10, 2, nil case 'r': return 13, 2, nil case 't': return 9, 2, nil case 'v': return 11, 2, nil case 'x': v, n := 0, 2 loop2: for _, r := range runes[2:] { switch { case r >= '0' && r <= '9', r >= 'a' && r <= 'f', r >= 'A' && r <= 'F': v = v<<4 | decodeHex(r) n++ if n >= 4 { break loop2 } default: break loop2 } } return rune(v & 0xff), n, nil case 'u', 'U': v, n := decodeUCN(runes) return v, n, nil } if r < '0' || r > '7' { return 0, 0, fmt.Errorf("illegal character '%s'", string(r)) } v, n := 0, 1 loop: for _, r := range runes[1:] { switch { case r >= '0' && r <= '7': v = v<<3 | (int(r) - '0') n++ if n >= 4 { break loop } default: break loop } } return rune(v), n, nil } func decodeHex(r rune) int { switch { case r >= '0' && r <= '9': return int(r) - '0' case r >= 'a' && r <= 'f', r >= 'A' && r <= 'F': x := int(r) &^ 0x20 return x - 'A' + 10 default: return -1 } } // universal-character-name \\u{hex-quad}|\\U{hex-quad}{hex-quad} func decodeUCN(runes []rune) (rune, int) { if runes[0] != '\\' { panic("internal error") } runes = runes[1:] switch runes[0] { case 'u': hq, n := decodeHexQuad(runes[1:]) return rune(hq), n + 2 case 'U': hq, n := decodeHexQuad(runes[1:]) if n == 4 { hq2, n2 := decodeHexQuad(runes[5:]) hq = hq << (4 * uint(n2)) hq = hq | hq2 n = n + n2 } return rune(hq), n + 2 default: panic("internal error") } } // hex-quad {hexadecimal-digit}{hexadecimal-digit}{hexadecimal-digit}{hexadecimal-digit} func decodeHexQuad(runes []rune) (int, int) { v, n := 0, 0 for _, r := range runes[:4] { h := decodeHex(r) if h < 0 { break } v = v<<4 | h n++ } return v, n } c2go-0.26.10/ast/character_literal_test.go000066400000000000000000000323721410601753200203450ustar00rootroot00000000000000package ast import ( "fmt" "github.com/elliotchance/c2go/cc" "io/ioutil" "os" "path" "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) } func TestCharacterLiteralDecodeHex(t *testing.T) { hexCodes := map[rune]int{ '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, 'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14, 'f': 15, 'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15, 'z': -1, // illegal hex characters return -1 'G': -1, } for r, expected := range hexCodes { i := decodeHex(r) if i != expected { t.Errorf("hexDecode should match: expected: %d, got: %d", expected, i) } } } func TestCharacterLiteralDecodeHexQuad(t *testing.T) { runes := map[string][]int{ "zzzzzz": {0, 0}, "1zzzzz": {0x1, 1}, "1Azzzz": {0x1a, 2}, "1A3zzz": {0x1a3, 3}, "1A3bzz": {0x1a3b, 4}, "1A3b5z": {0x1a3b, 4}, "1A3b": {0x1a3b, 4}, "1A3": {0x1a3, 3}, "1A": {0x1a, 2}, "1": {0x1, 1}, "": {0, 0}, } for r, expected := range runes { i, n := decodeHexQuad([]rune(r)) if int(i) != expected[0] { t.Errorf("hexDecodeQuad('%s') should match: expected: %x, got: %x", r, expected[0], i) } if n != expected[1] { t.Errorf("hexDecodeQuad('%s') length should match: expected: %d, got: %d", r, expected[1], n) } } } func TestCharacterLiteralDecodeUCN(t *testing.T) { runes := map[string][]int{ "\\uzzzzzz": {0, 2}, "\\u1zzzzz": {0x1, 3}, "\\u1Azzzz": {0x1a, 4}, "\\u1A3zzz": {0x1a3, 5}, "\\u1A3bzz": {0x1a3b, 6}, "\\u1A3b5z": {0x1a3b, 6}, "\\u1A3b": {0x1a3b, 6}, "\\u1A3": {0x1a3, 5}, "\\u1A": {0x1a, 4}, "\\u1": {0x1, 3}, "\\u": {0, 2}, "\\Uzzzzzzzzzz": {0, 2}, "\\U1zzzzzzzzz": {0x1, 3}, "\\U1Azzzzzzzz": {0x1a, 4}, "\\U1A3zzzzzzz": {0x1a3, 5}, "\\U1A3bzzzzzz": {0x1a3b, 6}, "\\U1A3b5zzzzz": {0x1a3b5, 7}, "\\U1A3b52zzzz": {0x1a3b52, 8}, "\\U1A3b52fzzz": {0x1a3b52f, 9}, "\\U1A3b52f6zz": {0x1a3b52f6, 10}, "\\U1A3b52f69z": {0x1a3b52f6, 10}, "\\U1A3b52f6": {0x1a3b52f6, 10}, "\\U1A3b52f": {0x1a3b52f, 9}, "\\U1A3b52": {0x1a3b52, 8}, "\\U1A3b5": {0x1a3b5, 7}, "\\U1A3b": {0x1a3b, 6}, "\\U1A3": {0x1a3, 5}, "\\U1A": {0x1a, 4}, "\\U1": {0x1, 3}, "\\U": {0, 2}, } for r, expected := range runes { i, n := decodeUCN([]rune(r)) if int(i) != expected[0] { t.Errorf("decodeUCN('%s') should match: expected: %x, got: %x", r, expected[0], int(i)) } if n != expected[1] { t.Errorf("decodeUCN('%s') length should match: expected: %d, got: %d", r, expected[1], n) } } } func TestCharacterLiteralDecodeEscapeSequence(t *testing.T) { type test struct { result int length int err error } runes := map[string]test{ "\\'zz": {int('\''), 2, nil}, "\\\"zz": {int('"'), 2, nil}, "\\?zz": {int('?'), 2, nil}, "\\\\zz": {int('\\'), 2, nil}, "\\azz": {int('\a'), 2, nil}, "\\bzz": {int('\b'), 2, nil}, "\\fzz": {int('\f'), 2, nil}, "\\nzz": {int('\n'), 2, nil}, "\\rzz": {int('\r'), 2, nil}, "\\tzz": {int('\t'), 2, nil}, "\\vzz": {int('\v'), 2, nil}, "\\'": {int('\''), 2, nil}, "\\\"": {int('"'), 2, nil}, "\\?": {int('?'), 2, nil}, "\\\\": {int('\\'), 2, nil}, "\\a": {int('\a'), 2, nil}, "\\b": {int('\b'), 2, nil}, "\\f": {int('\f'), 2, nil}, "\\n": {int('\n'), 2, nil}, "\\r": {int('\r'), 2, nil}, "\\t": {int('\t'), 2, nil}, "\\v": {int('\v'), 2, nil}, "\\xzzzzzz": {0, 2, nil}, "\\x3zzzzz": {0x3, 3, nil}, "\\x3bzzzz": {0x3b, 4, nil}, "\\x3b1zzz": {0x3b, 4, nil}, "\\x3b": {0x3b, 4, nil}, "\\x3": {0x3, 3, nil}, "\\x": {0, 2, nil}, "\\zzzzzz": {0, 0, fmt.Errorf("illegal character '%s'", "z")}, "\\dzzzzz": {0, 0, fmt.Errorf("illegal character '%s'", "d")}, "\\9zzzzz": {0, 0, fmt.Errorf("illegal character '%s'", "9")}, "\\z": {0, 0, fmt.Errorf("illegal character '%s'", "z")}, "\\d": {0, 0, fmt.Errorf("illegal character '%s'", "d")}, "\\9": {0, 0, fmt.Errorf("illegal character '%s'", "9")}, "\\0zzzzzz": {0, 2, nil}, "\\1zzzzzz": {1, 2, nil}, "\\2zzzzzz": {2, 2, nil}, "\\3zzzzzz": {3, 2, nil}, "\\4zzzzzz": {4, 2, nil}, "\\5zzzzzz": {5, 2, nil}, "\\6zzzzzz": {6, 2, nil}, "\\7zzzzzz": {7, 2, nil}, "\\0": {0, 2, nil}, "\\1": {1, 2, nil}, "\\2": {2, 2, nil}, "\\3": {3, 2, nil}, "\\4": {4, 2, nil}, "\\5": {5, 2, nil}, "\\6": {6, 2, nil}, "\\7": {7, 2, nil}, "\\34zzzzzz": {034, 3, nil}, "\\347zzzzz": {0347, 4, nil}, "\\3472zzzz": {0347, 4, nil}, "\\347": {0347, 4, nil}, "\\34": {034, 3, nil}, "\\uzzzzzz": {0, 2, nil}, "\\u1zzzzz": {0x1, 3, nil}, "\\u1Azzzz": {0x1a, 4, nil}, "\\u1A3zzz": {0x1a3, 5, nil}, "\\u1A3bzz": {0x1a3b, 6, nil}, "\\u1A3b5z": {0x1a3b, 6, nil}, "\\u1A3b": {0x1a3b, 6, nil}, "\\u1A3": {0x1a3, 5, nil}, "\\u1A": {0x1a, 4, nil}, "\\u1": {0x1, 3, nil}, "\\u": {0, 2, nil}, "\\Uzzzzzzzzzz": {0, 2, nil}, "\\U1zzzzzzzzz": {0x1, 3, nil}, "\\U1Azzzzzzzz": {0x1a, 4, nil}, "\\U1A3zzzzzzz": {0x1a3, 5, nil}, "\\U1A3bzzzzzz": {0x1a3b, 6, nil}, "\\U1A3b5zzzzz": {0x1a3b5, 7, nil}, "\\U1A3b52zzzz": {0x1a3b52, 8, nil}, "\\U1A3b52fzzz": {0x1a3b52f, 9, nil}, "\\U1A3b52f6zz": {0x1a3b52f6, 10, nil}, "\\U1A3b52f69z": {0x1a3b52f6, 10, nil}, "\\U1A3b52f6": {0x1a3b52f6, 10, nil}, "\\U1A3b52f": {0x1a3b52f, 9, nil}, "\\U1A3b52": {0x1a3b52, 8, nil}, "\\U1A3b5": {0x1a3b5, 7, nil}, "\\U1A3b": {0x1a3b, 6, nil}, "\\U1A3": {0x1a3, 5, nil}, "\\U1A": {0x1a, 4, nil}, "\\U1": {0x1, 3, nil}, "\\U": {0, 2, nil}, } for r, expected := range runes { i, n, err := decodeEscapeSequence([]rune(r)) if int(i) != expected.result { t.Errorf("decodeEscapeSequence('%s') should match: expected: %x, got: %x", r, expected.result, int(i)) } if n != expected.length { t.Errorf("decodeEscapeSequence('%s') length should match: expected: %d, got: %d", r, expected.length, n) } if err != nil && expected.err == nil || err == nil && expected.err != nil { t.Errorf("decodeEscapeSequence('%s') error should match: expected: %v, got: %v", r, expected.err, err) } else if err != nil && err.Error() != expected.err.Error() { t.Errorf("decodeEscapeSequence('%s') error should match: expected: %s, got: %s", r, expected.err.Error(), err.Error()) } } } func TestCharacterLiteralFromSource(t *testing.T) { type test struct { result int err error } prefixes := map[string]error{ "'": nil, "u'": nil, "u8'": nil, "U'": nil, "L'": nil, "z": fmt.Errorf("illegal character 'z' at index 0"), "uz": fmt.Errorf("illegal character 'z' at index 1"), "Uz": fmt.Errorf("illegal character 'z' at index 1"), "Lz": fmt.Errorf("illegal character 'z' at index 1"), "u8z": fmt.Errorf("illegal character 'z' at index 2"), } suffixes := map[string]test{ "": {0, fmt.Errorf("unexpected end of character literal")}, "'": {0, fmt.Errorf("empty character literal")}, "a'": {int('a'), nil}, "a": {0, fmt.Errorf("unexpected end of character literal")}, "\\": {0, fmt.Errorf("unexpected end of character literal")}, "\\'": {0, fmt.Errorf("unexpected end of character literal")}, "\\''": {int('\''), nil}, "ab": {0, fmt.Errorf("does not support multi-character literals")}, "\\nb": {0, fmt.Errorf("does not support multi-character literals")}, } tests := map[string]test{ "": {0, fmt.Errorf("character literal to short")}, "u": {0, fmt.Errorf("character literal to short")}, "u8": {0, fmt.Errorf("character literal to short")}, "U": {0, fmt.Errorf("character literal to short")}, "L": {0, fmt.Errorf("character literal to short")}, } for i, x := range prefixes { for j, y := range suffixes { var t = y str := i + j if x != nil { t.result = 0 t.err = x } tests[str] = t } } for s, expected := range tests { i, err := parseCharacterLiteralFromSource(s) if int(i) != expected.result { t.Errorf("parseCharacterLiteralFromSource('%s') should match: expected: %x, got: %x", s, expected.result, int(i)) } if err != nil && expected.err == nil || err == nil && expected.err != nil { t.Errorf("parseCharacterLiteralFromSource('%s') error should match: expected: %v, got: %v", s, expected.err, err) } else if err != nil && err.Error() != expected.err.Error() { t.Errorf("parseCharacterLiteralFromSource('%s') error should match: expected: %s, got: %s", s, expected.err.Error(), err.Error()) } } } func TestCharacterLiteralRepairFromSource(t *testing.T) { cl := &CharacterLiteral{ Addr: 0x7f980b858308, Pos: NewPositionFromString("col:12"), Type: "int", Value: 10, ChildNodes: []Node{}, } root := &CompoundStmt{ Pos: Position{File: "dummy.c", Line: 5}, ChildNodes: []Node{cl}, } FixPositions([]Node{root}) type test struct { file string expected int err error } tests := []test{ {"# 2 \"x.c\"\n\n", 10, fmt.Errorf("could not find file %s", "dummy.c")}, {"# 2 \"x.c\"\n\n# 1 \"dummy.c\"ff\nxxxxx\n\nyyyy", 10, fmt.Errorf("could not find %s:%d", "dummy.c", 5)}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = \nyyyy", 10, fmt.Errorf("cannot get exact value")}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = u\nyyyy", 10, fmt.Errorf("cannot parse character literal: character literal to short from u")}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = '\nyyyy", 10, fmt.Errorf("cannot parse character literal: unexpected end of character literal from '")}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = ''zzz\nyyyy", 10, fmt.Errorf("cannot parse character literal: empty character literal from ''zzz")}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = 'A'zzz\nyyyy", int('A'), nil}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = 'B'\nyyyy", int('B'), nil}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = '\\n'\nyyyy", int('\n'), nil}, } for _, test := range tests { prepareRepairFromSourceTest(t, test.file, func(ppFilePath string) { errors := RepairCharacterLiteralsFromSource(root, ppFilePath) if cl.Value != test.expected { t.Errorf("RepairCharacterLiteralsFromSource - expected: %x, got: %x", test.expected, cl.Value) } if test.err != nil && len(errors) == 0 || test.err == nil && len(errors) != 0 { t.Errorf("RepairCharacterLiteralsFromSource - error should match: expected: %v, got: %v", test.err, errors) } else if test.err != nil && errors[0].Err.Error() != test.err.Error() { t.Errorf("RepairCharacterLiteralsFromSource - error should match: expected: %s, got: %s", test.err.Error(), errors[0].Err.Error()) } }) } } func prepareRepairFromSourceTest(t *testing.T, fileContent string, test func(filePath string)) { cc.ResetCache() dir, err := ioutil.TempDir("", "c2go") if err != nil { t.Fatal(fmt.Errorf("Cannot create temp folder: %v", err)) } defer os.RemoveAll(dir) // clean up ppFilePath := path.Join(dir, "pp.c") err = ioutil.WriteFile(ppFilePath, []byte(fileContent), 0644) if err != nil { t.Fatal(fmt.Errorf("writing to %s failed: %v", ppFilePath, err)) } test(ppFilePath) } func TestCharacterLiteralRepairFromSourceMultiline(t *testing.T) { cl := &CharacterLiteral{ Addr: 0x7f980b858308, Pos: NewPositionFromString("col:12"), Type: "int", Value: 10, ChildNodes: []Node{}, } cl.Pos.LineEnd = 6 root := &CompoundStmt{ Pos: Position{File: "dummy.c", Line: 5}, ChildNodes: []Node{cl}, } FixPositions([]Node{root}) type test struct { file string expected int err error } tests := []test{ {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = '\nxxxxxxxxx, };\nyyyy", 10, fmt.Errorf("cannot parse character literal: illegal character '}' at index 0 from };")}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = 'A'zzz\nyyyy", int('A'), nil}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = {\nxxxxxxxxx, 'B'};\nyyyy", int('B'), nil}, } for _, test := range tests { prepareRepairFromSourceTest(t, test.file, func(ppFilePath string) { errors := RepairCharacterLiteralsFromSource(root, ppFilePath) if cl.Value != test.expected { t.Errorf("RepairCharacterLiteralsFromSource - expected: %x, got: %x", test.expected, cl.Value) } if test.err != nil && len(errors) == 0 || test.err == nil && len(errors) != 0 { t.Errorf("RepairCharacterLiteralsFromSource - error should match: expected: %v, got: %v", test.err, errors) } else if test.err != nil && errors[0].Err.Error() != test.err.Error() { t.Errorf("RepairCharacterLiteralsFromSource - error should match: expected: %s, got: %s", test.err.Error(), errors[0].Err.Error()) } }) } } c2go-0.26.10/ast/compound_assign_operator.go000066400000000000000000000032601410601753200207330ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/compound_assign_operator_test.go000066400000000000000000000010201410601753200217620ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/compound_literal_expr.go000066400000000000000000000024621410601753200202310ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/compound_literal_expr_test.go000066400000000000000000000006311410601753200212640ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/compound_stmt.go000066400000000000000000000023241410601753200165230ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/compound_stmt_test.go000066400000000000000000000007471410601753200175710ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/conditional_operator.go000066400000000000000000000023651410601753200200530ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/conditional_operator_test.go000066400000000000000000000005261410601753200211070ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/const_attr.go000066400000000000000000000023311410601753200160060ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/const_attr_test.go000066400000000000000000000005111410601753200170430ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/constant_array_type.go000066400000000000000000000023701410601753200177210ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/constant_array_type_test.go000066400000000000000000000007541410601753200207640ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/constant_expr.go000066400000000000000000000022611410601753200165170ustar00rootroot00000000000000package ast // ConstantExpr is a constant expression type ConstantExpr struct { Addr Address Pos Position Type string ChildNodes []Node } func parseConstantExpr(line string) *ConstantExpr { groups := groupsFromRegex( "<(?P.*)> '(?P.*?)'", line, ) return &ConstantExpr{ 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 *ConstantExpr) 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 *ConstantExpr) 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 *ConstantExpr) Children() []Node { return n.ChildNodes } // Position returns the position in the original source code. func (n *ConstantExpr) Position() Position { return n.Pos } c2go-0.26.10/ast/constant_expr_test.go000066400000000000000000000005341410601753200175570ustar00rootroot00000000000000package ast import ( "testing" ) func TestConstantExpr(t *testing.T) { nodes := map[string]Node{ `0x5558ffde68f0 'unsigned long'`: &ConstantExpr{ Addr: 0x5558ffde68f0, Pos: NewPositionFromString("col:34, col:55"), Type: "unsigned long", ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/continue_stmt.go000066400000000000000000000021641410601753200165250ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/continue_stmt_test.go000066400000000000000000000004221410601753200175570ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/decayed_type.go000066400000000000000000000021101410601753200162600ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/decayed_type_test.go000066400000000000000000000004511410601753200173250ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/decl_ref_expr.go000066400000000000000000000041731410601753200164350ustar00rootroot00000000000000package 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 NonODRUseUnevaluated bool ChildNodes []Node } func parseDeclRefExpr(line string) *DeclRefExpr { groups := groupsFromRegex( `<(?P.*)> '(?P.*?)'(:'(?P.*?)')? .*? (?P lvalue)? (?P\w+) (?P[0-9a-fx]+) '(?P.*?)' '(?P.*?)'(:'(?P.*?)')? (?P non_odr_use_unevaluated)? `, 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"], NonODRUseUnevaluated: len(groups["non_odr_use_unevaluated"]) > 0, 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 } c2go-0.26.10/ast/decl_ref_expr_test.go000066400000000000000000000054031410601753200174710ustar00rootroot00000000000000package 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{}, }, `0x55e2113b7970 'char [123]' lvalue Var 0x55e2113b7758 'a' 'char [123]' non_odr_use_unevaluated`: &DeclRefExpr{ Addr: 0x55e2113b7970, Pos: NewPositionFromString("col:16"), Type: "char [123]", Type1: "", Lvalue: true, For: "Var", Address2: "0x55e2113b7758", Name: "a", Type2: "char [123]", Type3: "", NonODRUseUnevaluated: true, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/decl_stmt.go000066400000000000000000000021511410601753200156040ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/decl_stmt_test.go000066400000000000000000000004521410601753200166450ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/default_stmt.go000066400000000000000000000021421410601753200163210ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/default_stmt_test.go000066400000000000000000000004701410601753200173620ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/deprecated_attr.go000066400000000000000000000027331410601753200167660ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/deprecated_attr_test.go000066400000000000000000000034631410601753200200260ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/disable_tail_calls_attr.go000066400000000000000000000023771410601753200204640ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/disable_tail_calls_attr_test.go000066400000000000000000000004571410601753200215200ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/do_stmt.go000066400000000000000000000020701410601753200152770ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/do_stmt_test.go000066400000000000000000000004561410601753200163440ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/elaborated_type.go000066400000000000000000000022371410601753200167760ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/elaborated_type_test.go000066400000000000000000000004751410601753200200370ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/empty_decl.go000066400000000000000000000022641410601753200157600ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/empty_decl_test.go000066400000000000000000000005031410601753200170110ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/enum.go000066400000000000000000000017731410601753200146030ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/enum_constant_decl.go000066400000000000000000000027401410601753200174760ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/enum_constant_decl_test.go000066400000000000000000000013021410601753200205260ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/enum_decl.go000066400000000000000000000025561410601753200155720ustar00rootroot00000000000000package ast import ( "strings" ) // EnumDecl is node represents a enum declaration. type EnumDecl struct { Addr Address Prev 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"]), Prev: ParseAddress(groups["prev"]), 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 } c2go-0.26.10/ast/enum_decl_test.go000066400000000000000000000016261410601753200166260ustar00rootroot00000000000000package 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{}, }, `0x5570ff477388 prev 0x5570ff445c40 line:1030:6 cb_assign_type`: &EnumDecl{ Addr: 0x5570ff477388, Prev: 0x5570ff445c40, Pos: NewPositionFromString("line:1030:1, line:1034:1"), Position2: " line:1030:6", Name: "cb_assign_type", ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/enum_test.go000066400000000000000000000003571410601753200156370ustar00rootroot00000000000000package ast import ( "testing" ) func TestEnum(t *testing.T) { nodes := map[string]Node{ `0x7f980b858308 'foo'`: &Enum{ Addr: 0x7f980b858308, Name: "foo", ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/enum_type.go000066400000000000000000000020451410601753200156350ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/enum_type_test.go000066400000000000000000000003671410601753200167010ustar00rootroot00000000000000package ast import ( "testing" ) func TestEnumType(t *testing.T) { nodes := map[string]Node{ `0x7f980b858309 'foo'`: &EnumType{ Addr: 0x7f980b858309, Name: "foo", ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/field.go000066400000000000000000000021211410601753200147060ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/field_decl.go000066400000000000000000000032101410601753200156750ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/field_decl_test.go000066400000000000000000000073101410601753200167410ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/field_test.go000066400000000000000000000006451410601753200157560ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/floating_literal.go000066400000000000000000000070231410601753200171500ustar00rootroot00000000000000package 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"), }) } else { var f float64 literal := line[pos.Column-1:] if _, err := fmt.Sscan(literal, &f); err == nil { fNode.Value = f } else { errs = append(errs, FloatingLiteralError{ Node: fNode, Err: fmt.Errorf("cannot parse float: %v from %s", err, literal), }) } } } return errs } c2go-0.26.10/ast/floating_literal_test.go000066400000000000000000000047621410601753200202160ustar00rootroot00000000000000package ast import ( "fmt" "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) } func TestFloatingLiteralRepairFromSource(t *testing.T) { fl := &FloatingLiteral{ Addr: 0x7febe106f5e8, Pos: NewPositionFromString("col:12"), Type: "double", Value: 1.23, ChildNodes: []Node{}, } root := &CompoundStmt{ Pos: Position{File: "dummy.c", Line: 5}, ChildNodes: []Node{fl}, } FixPositions([]Node{root}) type test struct { file string expected float64 err error } tests := []test{ {"# 2 \"x.c\"\n\n", 1.23, fmt.Errorf("could not find file %s", "dummy.c")}, {"# 2 \"x.c\"\n\n# 1 \"dummy.c\"ff\nxxxxx\n\nyyyy", 1.23, fmt.Errorf("could not find %s:%d", "dummy.c", 5)}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = \nyyyy", 1.23, fmt.Errorf("cannot get exact value")}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = u\nyyyy", 1.23, fmt.Errorf("cannot parse float: strconv.ParseFloat: parsing \"\": invalid syntax from u")}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = 3.5zzz\nyyyy", 3.5, nil}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = .7\nyyyy", 0.7, nil}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = -.4e2\nyyyy", -40, nil}, {"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = 0\nyyyy", 0, nil}, } for _, test := range tests { prepareRepairFromSourceTest(t, test.file, func(ppFilePath string) { errors := RepairFloatingLiteralsFromSource(root, ppFilePath) if fl.Value != test.expected { t.Errorf("RepairFloatingLiteralsFromSource - expected: %f, got: %f", test.expected, fl.Value) } if test.err != nil && len(errors) == 0 || test.err == nil && len(errors) != 0 { t.Errorf("RepairFloatingLiteralsFromSource - error should match: expected: %v, got: %v", test.err, errors) } else if test.err != nil && errors[0].Err.Error() != test.err.Error() { t.Errorf("RepairFloatingLiteralsFromSource - error should match: expected: %s, got: %s", test.err.Error(), errors[0].Err.Error()) } }) } } c2go-0.26.10/ast/for_stmt.go000066400000000000000000000021021410601753200154570ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/for_stmt_test.go000066400000000000000000000004561410601753200165300ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/format_arg_attr.go000066400000000000000000000023611410601753200170040ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/format_arg_attr_test.go000066400000000000000000000005041410601753200200400ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/format_attr.go000066400000000000000000000032251410601753200161530ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/format_attr_test.go000066400000000000000000000020431410601753200172070ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/full_comment.go000066400000000000000000000021431410601753200163130ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/full_comment_test.go000066400000000000000000000004721410601753200173550ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/function_decl.go000066400000000000000000000043051410601753200164450ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/function_decl_test.go000066400000000000000000000170051410601753200175050ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/function_no_proto_type.go000066400000000000000000000024271410601753200204410ustar00rootroot00000000000000package ast // FunctionNoProtoType is a function type without parameters. // // Example: // int (*)() type FunctionNoProtoType struct { Addr Address Type string CallingConv string ChildNodes []Node } func parseFunctionNoProtoType(line string) *FunctionNoProtoType { groups := groupsFromRegex( "'(?P.*?)' (?P.*)", line, ) return &FunctionNoProtoType{ Addr: ParseAddress(groups["address"]), Type: groups["type"], CallingConv: groups["calling_conv"], ChildNodes: []Node{}, } } // AddChild adds a new child node. Child nodes can then be accessed with the // Children attribute. func (n *FunctionNoProtoType) 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 *FunctionNoProtoType) 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 *FunctionNoProtoType) Children() []Node { return n.ChildNodes } // Position returns the position in the original source code. func (n *FunctionNoProtoType) Position() Position { return Position{} } c2go-0.26.10/ast/function_no_proto_type_test.go000066400000000000000000000004651410601753200215000ustar00rootroot00000000000000package ast import ( "testing" ) func TestFunctionNoProtoType(t *testing.T) { nodes := map[string]Node{ `0x556e32bfde50 'int ()' cdecl`: &FunctionNoProtoType{ Addr: 0x556e32bfde50, Type: "int ()", CallingConv: "cdecl", ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/function_proto_type.go000066400000000000000000000022761410601753200177470ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/function_proto_type_test.go000066400000000000000000000005211410601753200207750ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/gcc_asm_stmt.go000066400000000000000000000021451410601753200162740ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/gcc_asm_stmt_test.go000066400000000000000000000004621410601753200173330ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/go_stmt.go000066400000000000000000000023241410601753200153040ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/go_stmt_test.go000066400000000000000000000006201410601753200163400ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/html_end_tag_comment.go000066400000000000000000000023361410601753200200020ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/html_end_tag_comment_test.go000066400000000000000000000005111410601753200210320ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/html_start_tag_comment.go000066400000000000000000000023601410601753200203660ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/html_start_tag_comment_test.go000066400000000000000000000005151410601753200214250ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/if_stmt.go000066400000000000000000000022141410601753200152730ustar00rootroot00000000000000package ast // IfStmt is node represent 'if' type IfStmt struct { Addr Address Pos Position HasElse bool ChildNodes []Node } func parseIfStmt(line string) *IfStmt { groups := groupsFromRegex( "<(?P.*)>(?P has_else)?", line, ) return &IfStmt{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), HasElse: len(groups["has_else"]) > 0, 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 } c2go-0.26.10/ast/if_stmt_test.go000066400000000000000000000007711410601753200163400ustar00rootroot00000000000000package 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{}, }, `0x560d43f4ee98 has_else`: &IfStmt{ Addr: 0x560d43f4ee98, Pos: NewPositionFromString("line:65:2, line:72:2"), HasElse: true, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/implicit_cast_expr.go000066400000000000000000000032751410601753200175200ustar00rootroot00000000000000package ast // ImplicitCastExpr is expression. type ImplicitCastExpr struct { Addr Address Pos Position Type string Type2 string Kind string PartOfExplicitCast bool ChildNodes []Node } // ImplicitCastExprArrayToPointerDecay - constant const ImplicitCastExprArrayToPointerDecay = "ArrayToPointerDecay" func parseImplicitCastExpr(line string) *ImplicitCastExpr { groups := groupsFromRegex( `<(?P.*)> '(?P.*?)' (:'(?P.*?)')? <(?P.*)> (?P part_of_explicit_cast)?`, line, ) return &ImplicitCastExpr{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), Type: groups["type"], Type2: groups["type2"], Kind: groups["kind"], PartOfExplicitCast: len(groups["part_of_explicit_cast"]) > 0, 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 } c2go-0.26.10/ast/implicit_cast_expr_test.go000066400000000000000000000030371410601753200205530ustar00rootroot00000000000000package 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{}, }, `0x5600a8148b10 'unsigned int' part_of_explicit_cast`: &ImplicitCastExpr{ Addr: 0x5600a8148b10, Pos: NewPositionFromString("col:16"), Type: "unsigned int", Kind: "LValueToRValue", PartOfExplicitCast: true, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/implicit_value_init_expr.go000066400000000000000000000025411410601753200207200ustar00rootroot00000000000000package ast // ImplicitValueInitExpr is expression type ImplicitValueInitExpr struct { Addr Address Pos Position Type1 string Type2 string IsArrayFiller bool 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 } c2go-0.26.10/ast/implicit_value_init_expr_test.go000066400000000000000000000012071410601753200217550ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/incomplete_array_type.go000066400000000000000000000022241410601753200202250ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/incomplete_array_type_test.go000066400000000000000000000004241410601753200212640ustar00rootroot00000000000000package ast import ( "testing" ) func TestIncompleteArrayType(t *testing.T) { nodes := map[string]Node{ `0x7fcb7d005c20 'int []' `: &IncompleteArrayType{ Addr: 0x7fcb7d005c20, Type: "int []", ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/indirect_field_decl.go000066400000000000000000000030151410601753200175610ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/indirect_field_decl_test.go000066400000000000000000000006761410601753200206320ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/init_list_expr.go000066400000000000000000000023561410601753200166710ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/init_list_expr_test.go000066400000000000000000000015121410601753200177210ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/inline_command_comment.go000066400000000000000000000023641410601753200203320ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/inline_command_comment_test.go000066400000000000000000000005641410601753200213710ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/integer_literal.go000066400000000000000000000024071410601753200170030ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/integer_literal_test.go000066400000000000000000000005221410601753200200360ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/label_stmt.go000066400000000000000000000022261410601753200157570ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/label_stmt_test.go000066400000000000000000000005601410601753200170150ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/malloc_attr.go000066400000000000000000000022451410601753200161330ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/malloc_attr_test.go000066400000000000000000000004641410601753200171730ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/max_field_alignment_attr.go000066400000000000000000000026041410601753200206510ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/max_field_alignment_attr_test.go000066400000000000000000000010541410601753200217060ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/member_expr.go000066400000000000000000000046721410601753200161450ustar00rootroot00000000000000package 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 NonODRUseUnevaluated bool ChildNodes []Node } func parseMemberExpr(line string) *MemberExpr { groups := groupsFromRegex( `<(?P.*)> '(?P.*?)' (?P:'.*?')? (?P lvalue)? (?P bitfield)? (?P[->.]+) (?P\w+)? (?P[0-9a-fx]+) (?P non_odr_use_unevaluated)?`, 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"], NonODRUseUnevaluated: len(groups["non_odr_use_unevaluated"]) > 0, 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 } c2go-0.26.10/ast/member_expr_test.go000066400000000000000000000063131410601753200171760ustar00rootroot00000000000000package 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{}, }, `0x55dfff00bb30 'int' lvalue .x 0x55dfff00b7c8 non_odr_use_unevaluated`: &MemberExpr{ Addr: 0x55dfff00bb30, Pos: NewPositionFromString("col:16, col:18"), Type: "int", Type2: "", IsLvalue: true, IsBitfield: false, Name: "x", Address2: "0x55dfff00b7c8", IsPointer: false, NonODRUseUnevaluated: true, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/mode_attr.go000066400000000000000000000023211410601753200156030ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/mode_attr_test.go000066400000000000000000000005021410601753200166410ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/no_alias_attr.go000066400000000000000000000022341410601753200164470ustar00rootroot00000000000000package ast // NoAliasAttr is a type of attribute that is optionally attached to a function declaration. type NoAliasAttr struct { Addr Address Pos Position ChildNodes []Node } func parseNoAliasAttr(line string) *NoAliasAttr { groups := groupsFromRegex( "<(?P.*)>", line, ) return &NoAliasAttr{ 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 *NoAliasAttr) 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 *NoAliasAttr) 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 *NoAliasAttr) Children() []Node { return n.ChildNodes } // Position returns the position in the original source code. func (n *NoAliasAttr) Position() Position { return n.Pos } c2go-0.26.10/ast/no_alias_attr_test.go000066400000000000000000000004641410601753200175110ustar00rootroot00000000000000package ast import ( "testing" ) func TestNoAliasAttr(t *testing.T) { nodes := map[string]Node{ `0x7fa3b88bbb38 `: &NoAliasAttr{ Addr: 0x7fa3b88bbb38, Pos: NewPositionFromString("line:4:1, line:13:1"), ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/no_inline_attr.go000066400000000000000000000022671410601753200166420ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/no_inline_attr_test.go000066400000000000000000000004521410601753200176730ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/no_throw_attr.go000066400000000000000000000025421410601753200165230ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/no_throw_attr_test.go000066400000000000000000000017521410601753200175640ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/non_null_attr.go000066400000000000000000000035141410601753200165100ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/non_null_attr_test.go000066400000000000000000000043531410601753200175510ustar00rootroot00000000000000package 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{}, }, `0x2c3d600 `: &NonNullAttr{ Addr: 0x2c3d600, Pos: NewPositionFromString("line:304:19"), Inherited: false, A: 0, B: 0, C: 0, D: 0, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/not_tail_called_attr.go000066400000000000000000000023231410601753200177760ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/not_tail_called_attr_test.go000066400000000000000000000004511410601753200210350ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/offset_of_expr.go000066400000000000000000000022461410601753200166430ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/offset_of_expr_test.go000066400000000000000000000005341410601753200177000ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/packed_attr.go000066400000000000000000000022451410601753200161130ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/packed_attr_test.go000066400000000000000000000004421410601753200171470ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/paragraph_comment.go000066400000000000000000000022201410601753200173120ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/paragraph_comment_test.go000066400000000000000000000005041410601753200203540ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/param_command_comment.go000066400000000000000000000023531410601753200201520ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/param_command_comment_test.go000066400000000000000000000006461410601753200212140ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/paren_expr.go000066400000000000000000000025761410601753200160040ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/paren_expr_test.go000066400000000000000000000017211410601753200170320ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/paren_type.go000066400000000000000000000021221410601753200157720ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/paren_type_test.go000066400000000000000000000004421410601753200170340ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/parm_var_decl.go000066400000000000000000000037551410601753200164370ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/parm_var_decl_test.go000066400000000000000000000070501410601753200174660ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/pointer_type.go000066400000000000000000000021021410601753200163430ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/pointer_type_test.go000066400000000000000000000004531410601753200174110ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/position.go000066400000000000000000000230731410601753200155000ustar00rootroot00000000000000package 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 { if 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(`^((?:[a-zA-Z]\:)?[^:]+):(\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(`^((?:[a-zA-Z]\:)?[^:]+):(\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(`^((?:[a-zA-Z]\:)?[^:]+):(\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(`^((?:[a-zA-Z]\:)?[^:]+):(\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+), ((?:[a-zA-Z]\:)?[^:]+):(\d+):(\d+)$`) if groups := re.FindStringSubmatch(s); len(groups) > 0 { return Position{ StringValue: s, Column: util.Atoi(groups[1]), } } re = util.GetRegex(`^((?:[a-zA-Z]\:)?[^:]+):(\d+):(\d+), ((?:[a-zA-Z]\:)?[^:]+):(\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 *C11NoReturnAttr: 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 *ConstantExpr: 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 *NoAliasAttr: 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, *FunctionNoProtoType, *FunctionProtoType, *EnumType, *Enum, *ElaboratedType, *ConstantArrayType, *BuiltinType, *ArrayFiller, *Field, *AttributedType: // These do not have positions so they can be ignored. default: panic(fmt.Sprintf("unknown node type: %+#v", node)) } } c2go-0.26.10/ast/position_test.go000066400000000000000000000067351410601753200165450ustar00rootroot00000000000000package 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, }, `C:\usr\include\sys\cdefs.h:313:68`: { File: `C:\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, }, `C:\usr\include\AvailabilityInternal.h:21697:88, col:124`: { File: `C:\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, }, `C:\usr\include\secure\_stdio.h:42:1, line:43:32`: { File: `C:\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, }, `C:\usr\include\sys\stdio.h:39:1, C:\usr\include\AvailabilityInternal.h:21697:126`: { File: `C:\usr\include\sys\stdio.h`, Line: 39, Column: 1, LineEnd: 0, ColumnEnd: 0, }, `C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\math.h:39:1, C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\AvailabilityInternal.h:21697:126`: { File: `C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include\math.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, }, `col:1, C:\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) } }) } } c2go-0.26.10/ast/predefined_expr.go000066400000000000000000000024421410601753200167740ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/predefined_expr_test.go000066400000000000000000000006401410601753200200310ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/pure_attr.go000066400000000000000000000025041410601753200156350ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/pure_attr_test.go000066400000000000000000000010261410601753200166720ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/qual_type.go000066400000000000000000000021421410601753200156310ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/qual_type_test.go000066400000000000000000000004771410601753200167010ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/record.go000066400000000000000000000020141410601753200151020ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/record_decl.go000066400000000000000000000033631410601753200161010ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/record_decl_test.go000066400000000000000000000037201410601753200171350ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/record_test.go000066400000000000000000000003731410601753200161470ustar00rootroot00000000000000package ast import ( "testing" ) func TestRecord(t *testing.T) { nodes := map[string]Node{ `0x7fd3ab857950 '__sFILE'`: &Record{ Addr: 0x7fd3ab857950, Type: "__sFILE", ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/record_type.go000066400000000000000000000020701410601753200161450ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/record_type_test.go000066400000000000000000000004671410601753200172140ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/restrict_attr.go000066400000000000000000000023651410601753200165260ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/restrict_attr_test.go000066400000000000000000000005221410601753200175560ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/return_stmt.go000066400000000000000000000021401410601753200162120ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/return_stmt_test.go000066400000000000000000000004561410601753200172610ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/returns_twice_attr.go000066400000000000000000000026171410601753200175640ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/returns_twice_attr_test.go000066400000000000000000000010601410601753200206120ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/sentinel_attr.go000066400000000000000000000027111410601753200165030ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/sentinel_attr_test.go000066400000000000000000000005261410601753200175440ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/stmt_expr.go000066400000000000000000000022021410601753200156500ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/stmt_expr_test.go000066400000000000000000000005001410601753200167060ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/string_literal.go000066400000000000000000000027351410601753200166600ustar00rootroot00000000000000package 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.*)'(?P lvalue)? L?(?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: len(groups["lvalue"]) > 0, 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 } c2go-0.26.10/ast/string_literal_test.go000066400000000000000000000025031410601753200177100ustar00rootroot00000000000000package 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{}, }, `0x5632b5fa9818 'const char [4]' "foo"`: &StringLiteral{ Addr: 0x5632b5fa9818, Pos: NewPositionFromString("col:18"), Type: "const char [4]", Lvalue: false, Value: "foo", ChildNodes: []Node{}, }, `0x61b80c8 'wchar_t [21]' lvalue L"hello$$\x4F60\x597D\242\242\x4E16\x754C\x20AC\x20ACworld"`: &StringLiteral{ Addr: 0x61b80c8, Pos: NewPositionFromString("col:19"), Type: "wchar_t [21]", Lvalue: true, Value: "hello$$\x4F60\x597D\242\242\x4E16\x754C\x20AC\x20ACworld", ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/switch_stmt.go000066400000000000000000000021301410601753200161730ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/switch_stmt_test.go000066400000000000000000000004621410601753200172400ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/text_comment.go000066400000000000000000000022501410601753200163340ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/text_comment_test.go000066400000000000000000000005751410601753200174030ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/translation_unit_decl.go000066400000000000000000000022141410601753200202120ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/translation_unit_decl_test.go000066400000000000000000000004211410601753200212470ustar00rootroot00000000000000package ast import ( "testing" ) func TestTranslationUnitDecl(t *testing.T) { nodes := map[string]Node{ `0x7fe78a815ed0 <> `: &TranslationUnitDecl{ Addr: 0x7fe78a815ed0, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/transparent_union_attr.go000066400000000000000000000023671410601753200204420ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/transparent_union_attr_test.go000066400000000000000000000004421410601753200214710ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/traverse.go000066400000000000000000000011321410601753200154570ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/typedef.go000066400000000000000000000020251410601753200152660ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/typedef_decl.go000066400000000000000000000035241410601753200162620ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/typedef_decl_test.go000066400000000000000000000065351410601753200173260ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/typedef_test.go000066400000000000000000000004171410601753200163300ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/typedef_type.go000066400000000000000000000022001410601753200163220ustar00rootroot00000000000000package 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{} } c2go-0.26.10/ast/typedef_type_test.go000066400000000000000000000004511410601753200173670ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/unary_expr_or_type_trait_expr.go000066400000000000000000000030051410601753200220230ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/unary_expr_or_type_trait_expr_test.go000066400000000000000000000026401410601753200230660ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/unary_operator.go000066400000000000000000000032761410601753200167100ustar00rootroot00000000000000package ast // UnaryOperator is type of unary operator type UnaryOperator struct { Addr Address Pos Position Type string Type2 string IsLvalue bool IsPrefix bool Operator string CannotOverflow bool ChildNodes []Node } func parseUnaryOperator(line string) *UnaryOperator { groups := groupsFromRegex( `<(?P.*)> '(?P.*?)'(:'(?P.*)')? (?P lvalue)? (?P prefix)? (?P postfix)? '(?P.*?)' (?P cannot overflow)?`, 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"], CannotOverflow: len(groups["cannot_overflow"]) > 0, 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 } c2go-0.26.10/ast/unary_operator_test.go000066400000000000000000000033231410601753200177400ustar00rootroot00000000000000package 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{}, }, `0x55a7effc0878 'int' prefix '!' cannot overflow`: &UnaryOperator{ Addr: 0x55a7effc0878, Pos: NewPositionFromString("line:69:13, col:59"), Type: "int", Type2: "", IsLvalue: false, IsPrefix: true, Operator: "!", CannotOverflow: true, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/unused_attr.go000066400000000000000000000023631410601753200161700ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/unused_attr_test.go000066400000000000000000000007411410601753200172250ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/util.go000066400000000000000000000025651410601753200146140ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/va_arg_expr.go000066400000000000000000000022131410601753200161220ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/va_arg_expr_test.go000066400000000000000000000005041410601753200171620ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/var_decl.go000066400000000000000000000043721410601753200154140ustar00rootroot00000000000000package 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 IsNRVO 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 nrvo)? (?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, IsNRVO: len(groups["nrvo"]) > 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 } c2go-0.26.10/ast/var_decl_test.go000066400000000000000000000132661410601753200164550ustar00rootroot00000000000000package 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, IsNRVO: 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, IsNRVO: 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, IsNRVO: 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, IsNRVO: false, 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, IsNRVO: false, 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, IsNRVO: 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, IsNRVO: false, 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, IsNRVO: false, 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, IsNRVO: false, 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, IsNRVO: false, IsCInit: false, IsReferenced: false, IsStatic: false, IsRegister: false, Parent: 0x7f985e0246d0, ChildNodes: []Node{}, }, `0x55d681e87428 col:23 used variable 'union programming':'union programming' nrvo`: &VarDecl{ Addr: 0x55d681e87428, Pos: NewPositionFromString("col:5, col:23"), Position2: "col:23", Name: "variable", Type: "union programming", Type2: "union programming", IsExtern: false, IsUsed: true, IsNRVO: true, IsCInit: false, IsReferenced: false, IsStatic: false, IsRegister: false, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/verbatim_block_comment.go000066400000000000000000000025271410601753200203420ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/verbatim_block_comment_test.go000066400000000000000000000005711410601753200213760ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/verbatim_block_line_comment.go000066400000000000000000000024361410601753200213500ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/verbatim_block_line_comment_test.go000066400000000000000000000005671410601753200224120ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/verbatim_line_comment.go000066400000000000000000000023601410601753200201720ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/verbatim_line_comment_test.go000066400000000000000000000005531410601753200212330ustar00rootroot00000000000000package 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) } c2go-0.26.10/ast/visibility_attr.go000066400000000000000000000026531410601753200170560ustar00rootroot00000000000000package ast // VisibilityAttr contains information for a VisibilityAttr AST line. type VisibilityAttr struct { Addr Address Pos Position ChildNodes []Node IsDefault bool IsInherited bool IsHidden bool } func parseVisibilityAttr(line string) *VisibilityAttr { groups := groupsFromRegex( `<(?P.*)> (?P Inherited)? (?P Default)? (?P Hidden)? `, line, ) return &VisibilityAttr{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), ChildNodes: []Node{}, IsDefault: len(groups["default"]) > 0, IsInherited: len(groups["inherited"]) > 0, IsHidden: len(groups["hidden"]) > 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 } c2go-0.26.10/ast/visibility_attr_test.go000066400000000000000000000016511410601753200201120ustar00rootroot00000000000000package 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, IsHidden: false, }, `0x7f8e7b00bb80 Inherited Default`: &VisibilityAttr{ Addr: 0x7f8e7b00bb80, Pos: NewPositionFromString("/cmark/src/cmark.h:497:16, col:36"), ChildNodes: []Node{}, IsInherited: true, IsDefault: true, IsHidden: false, }, `0x55ab30581650 Hidden`: &VisibilityAttr{ Addr: 0x55ab30581650, Pos: NewPositionFromString("line:24:16, col:35"), ChildNodes: []Node{}, IsInherited: false, IsDefault: false, IsHidden: true, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/warn_unused_result_attr.go000066400000000000000000000025521410601753200206150ustar00rootroot00000000000000package 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 Inherited bool ChildNodes []Node } func parseWarnUnusedResultAttr(line string) *WarnUnusedResultAttr { groups := groupsFromRegex(`<(?P.*)>(?P Inherited)?( warn_unused_result)?( "")?`, line) return &WarnUnusedResultAttr{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), 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 *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 } c2go-0.26.10/ast/warn_unused_result_attr_test.go000066400000000000000000000017531410601753200216560ustar00rootroot00000000000000package ast import ( "testing" ) func TestWarnUnusedResultAttr(t *testing.T) { nodes := map[string]Node{ `0x7fa1d704d420 warn_unused_result`: &WarnUnusedResultAttr{ Addr: 0x7fa1d704d420, Pos: NewPositionFromString("col:60"), Inherited: false, ChildNodes: []Node{}, }, `0x1fac810 `: &WarnUnusedResultAttr{ Addr: 0x1fac810, Pos: NewPositionFromString("line:481:52"), Inherited: false, ChildNodes: []Node{}, }, `0x3794590 Inherited`: &WarnUnusedResultAttr{ Addr: 0x3794590, Pos: NewPositionFromString("/home/kph/co/util-linux/libblkid/src/blkidP.h:374:19"), Inherited: true, ChildNodes: []Node{}, }, `0x55c2df4f93b8 warn_unused_result ""`: &WarnUnusedResultAttr{ Addr: 0x55c2df4f93b8, Pos: NewPositionFromString("col:53"), Inherited: false, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/weak_attr.go000066400000000000000000000021541410601753200156120ustar00rootroot00000000000000package ast // WeakAttr for the WeakAttr node type WeakAttr struct { Addr Address Pos Position Inherited bool ChildNodes []Node } func parseWeakAttr(line string) *WeakAttr { groups := groupsFromRegex( `<(?P.*)>(?P Inherited)?`, line, ) return &WeakAttr{ Addr: ParseAddress(groups["address"]), Pos: NewPositionFromString(groups["position"]), Inherited: len(groups["inherited"]) > 0, 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 } c2go-0.26.10/ast/weak_attr_test.go000066400000000000000000000010561410601753200166510ustar00rootroot00000000000000package ast import ( "testing" ) func TestWeakAttr(t *testing.T) { nodes := map[string]Node{ `0x56069ece5110 `: &WeakAttr{ Addr: 0x56069ece5110, Pos: NewPositionFromString("line:736:22"), Inherited: false, ChildNodes: []Node{}, }, `0x20c6ad0 Inherited`: &WeakAttr{ Addr: 0x20c6ad0, Pos: NewPositionFromString("/glibc-2.27/support/temp_file-internal.h:27:62"), Inherited: true, ChildNodes: []Node{}, }, } runNodeTests(t, nodes) } c2go-0.26.10/ast/while_stmt.go000066400000000000000000000021261410601753200160070ustar00rootroot00000000000000package 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 } c2go-0.26.10/ast/while_stmt_test.go000066400000000000000000000004601410601753200170450ustar00rootroot00000000000000package 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) } c2go-0.26.10/cc/000077500000000000000000000000001410601753200130765ustar00rootroot00000000000000c2go-0.26.10/cc/preprocessor.go000066400000000000000000000036531410601753200161620ustar00rootroot00000000000000package cc import ( "fmt" "io/ioutil" "strings" "github.com/elliotchance/c2go/util" ) // fileCache contains the previous read files. This is important because // rereading large preprocessed files is extremely expensive and they should not // change during the life of the executable. var fileCache map[string]map[int]string // ResetCache must be called before the next transpile happens if the executable // is being used to transpile multiple files. func ResetCache() { fileCache = nil } // GetLineFromPreprocessedFile returns a specific line for a file from a // preprocessed C file. func GetLineFromPreprocessedFile(inputFilePath, filePath string, lineNumber int) (string, error) { // Only load the file once. if fileCache == nil { fileCache = map[string]map[int]string{} inputFile, err := ioutil.ReadFile(inputFilePath) if err != nil { return "", err } lines := strings.Split(string(inputFile), "\n") currentFile := "" currentLine := 1 // There is also an integer that appears after the path - not sure what this // is? I will ignore it for now. resetLineRegexp := util.GetRegex(`^# (\d+) "(.+)"`) for _, line := range lines { if len(line) > 0 && line[0] == '#' { matches := resetLineRegexp.FindStringSubmatch(line) // Ignore other preprocessor lines like: #pragma pack(4) if len(matches) == 0 { continue } currentLine = util.Atoi(matches[1]) // unescape windows file paths currentFile = strings.Replace(matches[2], "\\\\", "\\", -1) if _, ok := fileCache[currentFile]; !ok { fileCache[currentFile] = map[int]string{} } continue } fileCache[currentFile][currentLine] = line currentLine++ } } if _, ok := fileCache[filePath]; !ok { return "", fmt.Errorf("could not find file %s", filePath) } if line, ok := fileCache[filePath][lineNumber]; ok { return line, nil } return "", fmt.Errorf("could not find %s:%d", filePath, lineNumber) } c2go-0.26.10/cli_test.go000066400000000000000000000021061410601753200146450ustar00rootroot00000000000000package main import ( "bytes" "os" "testing" "github.com/bradleyjkemp/cupaloy" ) func setupTest(args []string) (*bytes.Buffer, func()) { buf := &bytes.Buffer{} oldStderr := stderr oldArgs := os.Args stderr = buf os.Args = args return buf, func() { stderr = oldStderr os.Args = oldArgs } } var cliTests = map[string][]string{ // Test that help is printed if no files are given "TranspileNoFilesHelp": {"test", "transpile"}, // Test that help is printed if help flag is set, even if file is given "TranspileHelpFlag": {"test", "transpile", "-h", "foo.c"}, // Test that help is printed if no files are given "AstNoFilesHelp": {"test", "ast"}, // Test that help is printed if help flag is set, even if file is given "AstHelpFlag": {"test", "ast", "-h", "foo.c"}, } func TestCLI(t *testing.T) { for testName, args := range cliTests { t.Run(testName, func(t *testing.T) { output, teardown := setupTest(args) defer teardown() runCommand() err := cupaloy.SnapshotMulti(testName, output) if err != nil { t.Fatalf("error: %s", err) } }) } } c2go-0.26.10/codecov.yml000066400000000000000000000004711410601753200146600ustar00rootroot00000000000000coverage: status: project: default: threshold: 100% if_no_uploads: error if_not_found: success if_ci_failed: error patch: default: enabled: yes target: 0% if_no_uploads: error if_not_found: success if_ci_failed: error c2go-0.26.10/darwin/000077500000000000000000000000001410601753200137755ustar00rootroot00000000000000c2go-0.26.10/darwin/assert.go000066400000000000000000000011061410601753200156230ustar00rootroot00000000000000package darwin import ( "fmt" "os" "github.com/elliotchance/c2go/noarch" ) // BuiltinExpect handles __builtin_expect(). func BuiltinExpect(a, b int32) int32 { return noarch.BoolToInt(a != b) } // AssertRtn handles __assert_rtn(). func AssertRtn( functionName, filePath *byte, lineNumber int32, expression *byte, ) bool { fmt.Fprintf( os.Stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", noarch.CStringToString(expression), noarch.CStringToString(functionName), noarch.CStringToString(filePath), lineNumber, ) os.Exit(134) return true } c2go-0.26.10/darwin/builtin.go000066400000000000000000000010761410601753200157760ustar00rootroot00000000000000// Package darwin contains low-level functions for the Darwin (macOS) operating // system. package darwin // BSwap32 handles __builtin_bswap32(). It is not supported and if used with // panic. The original documentation says: // // Returns x with the order of the bytes reversed; for example, 0xaabb becomes // 0xbbaa. Byte here always means exactly 8 bits. func BSwap32(a uint32) uint32 { panic("BSwap32 is not supported") } // BSwap64 handles __builtin_bswap64(). It is not supported, see BSwap32(). func BSwap64(a uint64) uint64 { panic("BSwap64 is not supported") } c2go-0.26.10/darwin/ctype.go000066400000000000000000000076021410601753200154550ustar00rootroot00000000000000package darwin import ( "unicode" "unicode/utf8" ) // CtRuneT represents __darwin_ct_rune_t. type CtRuneT int32 // Apple defines a bunch of magic values for the type of character, see // https://opensource.apple.com/source/Libc/Libc-320/include/ctype.h.auto.html // // These are provided as values for method that take _f parameter. const ( CtypeA = 0x00000100 // Alpha CtypeC = 0x00000200 // Control CtypeD = 0x00000400 // Digit CtypeG = 0x00000800 // Graph CtypeL = 0x00001000 // Lower CtypeP = 0x00002000 // Punct CtypeS = 0x00004000 // Space CtypeU = 0x00008000 // Upper CtypeX = 0x00010000 // X digit CtypeB = 0x00020000 // Blank CtypeR = 0x00040000 // Print CtypeI = 0x00080000 // Ideogram CtypeT = 0x00100000 // Special CtypeQ = 0x00200000 // Phonogram CtypeSW0 = 0x20000000 // 0 width character CtypeSW1 = 0x40000000 // 1 width character CtypeSW2 = 0x80000000 // 2 width character CtypeSW3 = 0xc0000000 // 3 width character ) // IsType replaces __istype(). It should not be strictly necessary but the real // __istype() refers to internal darwin state (_DefaultRuneLocale) that is // difficult to translate. So for now we will replace it but this could be // removed in the future. // // There may be multiple bit masks. And yes, I'm sure there is a much better way // to handle this, so if you know one please consider putting in a PR :) func IsType(_c CtRuneT, _f uint32) uint32 { // These are the easy ones. if _f&CtypeA != 0 && unicode.IsLetter(rune(_c)) && rune(_c) < 0x80 { return 1 } if _f&CtypeC != 0 && unicode.IsControl(rune(_c)) && rune(_c) < 0x80 { return 1 } if _f&CtypeD != 0 && unicode.IsDigit(rune(_c)) && rune(_c) < 0x80 { return 1 } // The IsSpace check is required because Go treats spaces as graphic // characters, which C does not. if _f&CtypeG != 0 && unicode.IsGraphic(rune(_c)) && !unicode.IsSpace(rune(_c)) && rune(_c) < 0x80 { return 1 } if _f&CtypeL != 0 && unicode.IsLower(rune(_c)) && rune(_c) < 0x80 { return 1 } // Need to check for 0x24, 0x2b, 0x3c-0x3e, 0x5e, 0x60, 0x7c, 0x7e // because Go doesn't treat $+<=>^`|~ as punctuation. if _f&CtypeP != 0 && rune(_c) < 0x80 && (unicode.IsPunct(rune(_c)) || rune(_c) == 0x24 || rune(_c) == 0x2b || (rune(_c) >= 0x3c && rune(_c) <= 0x3e) || rune(_c) == 0x5e || rune(_c) == 0x60 || rune(_c) == 0x7c || rune(_c) == 0x7e) { return 1 } if _f&CtypeS != 0 && unicode.IsSpace(rune(_c)) && rune(_c) < 0x80 { return 1 } if _f&CtypeU != 0 && unicode.IsUpper(rune(_c)) && rune(_c) < 0x80 { return 1 } if _f&CtypeR != 0 && unicode.IsPrint(rune(_c)) && rune(_c) < 0x80 { return 1 } // TODO: Is this really the right way to do this? if _f&CtypeX != 0 && (unicode.IsDigit(rune(_c)) || (_c >= 'a' && _c <= 'f') || (_c >= 'A' && _c <= 'F')) && rune(_c) < 0x80 { return 1 } // These are not supported, yet. if _f&CtypeB != 0 { panic("CtypeB is not supported") } if _f&CtypeI != 0 { panic("CtypeI is not supported") } if _f&CtypeT != 0 { panic("CtypeT is not supported") } if _f&CtypeQ != 0 { panic("CtypeQ is not supported") } // Extra rules around the character width (in bytes). _, size := utf8.DecodeLastRuneInString(string(_c)) if _f&CtypeSW0 != 0 && size == 0 { return 1 } if _f&CtypeSW1 != 0 && size == 1 { return 1 } if _f&CtypeSW2 != 0 && size == 2 { return 1 } if _f&CtypeSW3 != 0 && size == 3 { return 1 } return 0 } // MaskRune handles __maskrune(). I have no idea what MaskRune is supposed to // do. It is provided internally by darwin. func MaskRune(_c CtRuneT, _f uint32) CtRuneT { return _c } // IsCType handles __isctype. func IsCType(_c CtRuneT, _f uint32) CtRuneT { return CtRuneT(IsType(_c, _f)) } // ToLower handles __tolower(). func ToLower(_c CtRuneT) CtRuneT { return CtRuneT(unicode.ToLower(rune(_c))) } // ToUpper handles __toupper(). func ToUpper(_c CtRuneT) CtRuneT { return CtRuneT(unicode.ToUpper(rune(_c))) } c2go-0.26.10/darwin/math.go000066400000000000000000000025451410601753200152630ustar00rootroot00000000000000package darwin import ( "math" ) // Float2 is used by the functions that end with "Stret". It replaces the // internal macOS type of __float2. type Float2 struct { Sinval float32 Cosval float32 } // Double2 is used by the functions that end with "Stret". It replaces the // internal macOS type of __double2. type Double2 struct { Sinval float64 Cosval float64 } // Fabsf handles __builtin_fabsf(). func Fabsf(x float32) float32 { return float32(math.Abs(float64(x))) } // Fabs handles __builtin_fabs(). func Fabs(x float64) float64 { return math.Abs(x) } // Fabsl handles __builtin_fabsl(). func Fabsl(x float64) float64 { return math.Abs(x) } // Inff handles __builtin_inff(). func Inff() float32 { return float32(math.Inf(0)) } // Inf handles __builtin_inf(). func Inf() float64 { return math.Inf(0) } // Infl handles __builtin_infl(). func Infl() float64 { return math.Inf(0) } // SincosfStret handles __sincosf_stret(). func SincosfStret(x float32) Float2 { return Float2{0, 0} } // SincosStret handles __sincos_stret(). func SincosStret(x float64) Double2 { return Double2{0, 0} } // SincospifStret handles __sincospif_stret(). func SincospifStret(x float32) Float2 { return Float2{0, 0} } // SincospiStret handles __sincospi_stret(). func SincospiStret(x float64) Double2 { return Double2{0, 0} } func NaN(s *byte) float64 { return math.NaN() } c2go-0.26.10/darwin/stdio.go000066400000000000000000000016431410601753200154520ustar00rootroot00000000000000package darwin import "github.com/elliotchance/c2go/noarch" // BuiltinVsprintfChk - implementation __builtin___vsprintf_chk func BuiltinVsprintfChk(buffer *byte, _ int32, n int32, format *byte, args noarch.VaList) int32 { return noarch.Sprintf(buffer, format, args.Args) } // BuiltinVsnprintfChk - implementation __builtin___vsnprintf_chk func BuiltinVsnprintfChk(buffer *byte, n int32, _ int32, _ int32, format *byte, args noarch.VaList) int32 { return noarch.Sprintf(buffer, format, args.Args) } // BuiltinSprintfChk - implementation __builtin___sprintf_chk func BuiltinSprintfChk(buffer *byte, _ int32, n int32, format *byte, args ...interface{}) int32 { return noarch.Sprintf(buffer, format, args) } // BuiltinSnprintfChk - implementation __builtin___snprintf_chk func BuiltinSnprintfChk(buffer *byte, n int32, _ int32, _ int32, format *byte, args ...interface{}) int32 { return noarch.Sprintf(buffer, format, args) } c2go-0.26.10/darwin/string.go000066400000000000000000000026261410601753200156400ustar00rootroot00000000000000package darwin import ( "github.com/elliotchance/c2go/noarch" "unsafe" ) // BuiltinStrcpy is for __builtin___strcpy_chk. // https://opensource.apple.com/source/Libc/Libc-498/include/secure/_string.h func BuiltinStrcpy(dest, src *byte, size int32) *byte { return noarch.Strcpy(dest, src) } // BuiltinObjectSize is for __builtin_object_size. // https://github.com/elliotchance/c2go/issues/359 func BuiltinObjectSize(ptr *byte, theType int32) int32 { return 5 } // BuiltinStrncpy is for __builtin___strncpy_chk. // https://opensource.apple.com/source/Libc/Libc-498/include/secure/_string.h func BuiltinStrncpy(dest, src *byte, len, size int32) *byte { return noarch.Strncpy(dest, src, len) } // BuiltinStrcat is for __builtin___strcat_chk // https://opensource.apple.com/source/Libc/Libc-763.12/include/secure/_string.h.auto.html func BuiltinStrcat(dest, src *byte, _ int32) *byte { return noarch.Strcat(dest, src) } // Memset is for __builtin___memset_chk // https://opensource.apple.com/source/Libc/Libc-498/include/secure/_string.h func Memset(dst unsafe.Pointer, val int32, size int32, _ int32) unsafe.Pointer { return noarch.Memset(dst, val, size) } // Memcpy is for __builtin___memcpy_chk and __builtin___memmove_chk //// https://opensource.apple.com/source/Libc/Libc-498/include/secure/_string.h func Memcpy(dst, src unsafe.Pointer, size int32, _ int32) unsafe.Pointer { return noarch.Memcpy(dst, src, size) } c2go-0.26.10/examples/000077500000000000000000000000001410601753200143275ustar00rootroot00000000000000c2go-0.26.10/examples/fib.c000066400000000000000000000005701410601753200152350ustar00rootroot00000000000000#include int main() { int n = 5, first = 0, second = 1, next, c; printf("First %d terms of Fibonacci series are :-\n",n); for ( c = 0 ; c < n ; c++ ) { if ( c <= 1 ) next = c; else { next = first + second; first = second; second = next; } printf("%d\n",next); } return 0; } c2go-0.26.10/examples/prime.c000066400000000000000000000006741410601753200156160ustar00rootroot00000000000000#include int main() { int n, c; printf("Enter a number\n"); scanf("%d", &n); printf("The number is: %d\n", n); if (n == 2) printf("Prime number.\n"); else { for (c = 2; c <= n - 1; c++) { if (n % c == 0) break; } if (c != n) printf("Not prime.\n"); else printf("Prime number.\n"); } return 0; } c2go-0.26.10/go.mod000066400000000000000000000001431410601753200136150ustar00rootroot00000000000000module github.com/elliotchance/c2go require golang.org/x/tools v0.0.0-20181109182537-4e34152f1676 c2go-0.26.10/go.sum000066400000000000000000000003231410601753200136420ustar00rootroot00000000000000golang.org/x/tools v0.0.0-20181109182537-4e34152f1676 h1:mN8PuedDn93qQ+61nw3sKgjrKb7T8lx8DpUI2LwPH5U= golang.org/x/tools v0.0.0-20181109182537-4e34152f1676/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= c2go-0.26.10/linux/000077500000000000000000000000001410601753200136505ustar00rootroot00000000000000c2go-0.26.10/linux/assert.go000066400000000000000000000007031410601753200155000ustar00rootroot00000000000000package linux import ( "fmt" "os" "github.com/elliotchance/c2go/noarch" ) // AssertFail handles __assert_fail(). func AssertFail( expression, filePath *byte, lineNumber uint32, functionName *byte, ) bool { fmt.Fprintf( os.Stderr, "a.out: %s:%d: %s: Assertion `%s' failed.\n", noarch.CStringToString(filePath), lineNumber, noarch.CStringToString(functionName), noarch.CStringToString(expression), ) os.Exit(134) return true } c2go-0.26.10/linux/builtin.go000066400000000000000000000001341410601753200156430ustar00rootroot00000000000000// Package linux contains low-level functions for the Linux operating system. package linux c2go-0.26.10/linux/ctype.go000066400000000000000000000044331410601753200153270ustar00rootroot00000000000000package linux import ( "unicode" "unsafe" ) var characterTable []uint16 func generateCharacterTable() { for i := 0; i < 0x80; i++ { var c uint16 // Each of the bitwise expressions below were copied from the enum // values, like _ISupper, etc. if unicode.IsUpper(rune(i)) { c |= ((1 << (0)) << 8) } if unicode.IsLower(rune(i)) { c |= ((1 << (1)) << 8) } if unicode.IsLetter(rune(i)) { c |= ((1 << (2)) << 8) } if unicode.IsDigit(rune(i)) { c |= ((1 << (3)) << 8) } if unicode.IsDigit(rune(i)) || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F') { // IsXDigit. This is the same implementation as the Mac version. // There may be a better way to do this. c |= ((1 << (4)) << 8) } if unicode.IsSpace(rune(i)) { c |= ((1 << (5)) << 8) } if unicode.IsPrint(rune(i)) { c |= ((1 << (6)) << 8) } // The IsSpace check is required because Go treats spaces as graphic // characters, which C does not. if unicode.IsGraphic(rune(i)) && !unicode.IsSpace(rune(i)) { c |= ((1 << (7)) << 8) } // FIXME: Blank is not implemented. // if unicode.IsBlank(rune(i)) { // c |= ((1 << (8)) >> 8) // } if unicode.IsControl(rune(i)) { c |= ((1 << (9)) >> 8) } // Need to check for 0x24, 0x2b, 0x3c-0x3e, 0x5e, 0x60, 0x7c, 0x7e // because Go doesn't treat $+<=>^`|~ as punctuation. if unicode.IsPunct(rune(i)) || i == 0x24 || i == 0x2b || (i >= 0x3c && i <= 0x3e) || i == 0x5e || i == 0x60 || i == 0x7c || i == 0x7e { c |= ((1 << (10)) >> 8) } if unicode.IsLetter(rune(i)) || unicode.IsDigit(rune(i)) { c |= ((1 << (11)) >> 8) } // Yes, I know this is a hideously slow way to do it but I just want to // test if this works right now. characterTable = append(characterTable, c) } for i := 0x80; i < 256; i++ { // false for all characters > 0x7f characterTable = append(characterTable, 0) } } // CtypeLoc handles __ctype_b_loc(). It returns a character table. func CtypeLoc() **uint16 { if len(characterTable) == 0 { generateCharacterTable() } return (**uint16)(unsafe.Pointer(&characterTable)) } // ToLower handles tolower(). func ToLower(_c int32) int32 { return int32(unicode.ToLower(rune(_c))) } // ToUpper handles toupper(). func ToUpper(_c int32) int32 { return int32(unicode.ToUpper(rune(_c))) } c2go-0.26.10/linux/math.go000066400000000000000000000004771410601753200151400ustar00rootroot00000000000000package linux import ( "math" "github.com/elliotchance/c2go/noarch" ) func IsNanf(x float32) int32 { return noarch.BoolToInt(math.IsNaN(float64(x))) } func IsInff(x float32) int32 { return noarch.BoolToInt(math.IsInf(float64(x), 0)) } func IsInf(x float64) int32 { return noarch.BoolToInt(math.IsInf(x, 0)) } c2go-0.26.10/main.go000066400000000000000000000252171410601753200137730ustar00rootroot00000000000000// Package c2go contains the main function for running the executable. // // Installation // // go get -u github.com/elliotchance/c2go // // Usage // // c2go transpile myfile.c // package main import ( "flag" "fmt" "io" "io/ioutil" "os" "os/exec" "path" "path/filepath" "runtime" "strings" "errors" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/preprocessor" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/transpiler" ) var stderr io.Writer = os.Stderr // ProgramArgs defines the options available when processing the program. There // is no constructor since the zeroed out values are the appropriate defaults - // you need only set the options you need. // // TODO: Better separation on CLI modes // https://github.com/elliotchance/c2go/issues/134 // // Do not instantiate this directly. Instead use DefaultProgramArgs(); then // modify any specific attributes. 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 ...") } // 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 if args.verbose { fmt.Println("Running clang preprocessor...") } pp, comments, includes, err := preprocessor.Analyze(args.inputFiles, args.clangFlags, args.verbose) if err != nil { return fmt.Errorf("issue running preprocessor: %w", err) } if args.verbose { fmt.Println("Writing preprocessor ...") } dir, err := ioutil.TempDir("", "c2go") if err != nil { return fmt.Errorf("Cannot create temp folder: %v", err) } defer os.RemoveAll(dir) // clean up ppFilePath := path.Join(dir, "pp.c") err = ioutil.WriteFile(ppFilePath, pp, 0644) if err != nil { return fmt.Errorf("writing to %s failed: %v", ppFilePath, err) } // 3. Generate JSON from AST if args.verbose { fmt.Println("Running clang for AST tree...") } astPP, err := exec.Command("clang", "-Xclang", "-ast-dump", "-fsyntax-only", "-fno-color-diagnostics", ppFilePath).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", ppFilePath).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 } p := program.NewProgram() p.Verbose = args.verbose p.OutputAsTest = args.outputAsTest p.Comments = comments p.IncludeHeaders = includes // 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) ast.FixPositions(tree) p.SetNodes(tree) // Repair the character literals. See RepairCharacterLiteralsFromSource for // more information. characterErrors := ast.RepairCharacterLiteralsFromSource(tree[0], ppFilePath) for _, cErr := range characterErrors { message := fmt.Sprintf("could not read exact character literal: %s", cErr.Err.Error()) p.AddMessage(p.GenerateWarningMessage(errors.New(message), cErr.Node)) } // Repair the floating literals. See RepairFloatingLiteralsFromSource for // more information. floatingErrors := ast.RepairFloatingLiteralsFromSource(tree[0], ppFilePath) for _, fErr := range floatingErrors { message := fmt.Sprintf("could not read exact floating literal: %s", fErr.Err.Error()) p.AddMessage(p.GenerateWarningMessage(errors.New(message), fErr.Node)) } outputFilePath := args.outputFile if outputFilePath == "" { // Choose inputFile for creating name of output file input := args.inputFiles[0] // We choose name for output Go code at the base // on filename for choosed input file cleanFileName := filepath.Clean(filepath.Base(input)) extension := filepath.Ext(input) outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go" } // transpile ast tree if args.verbose { fmt.Println("Transpiling tree...") } err = transpiler.TranspileAST(args.outputFile, args.packageName, p, tree[0].(ast.Node)) if err != nil { return fmt.Errorf("cannot transpile AST : %v", err) } // write the output Go code if args.verbose { fmt.Println("Writing the output Go code...") } err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0644) if err != nil { return fmt.Errorf("writing Go output file failed: %v", err) } // simplify Go code by `gofmt` // error ignored, because it is not change the workflow _, _ = exec.Command("gofmt", "-w", outputFilePath).Output() 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.Fprintf(stderr, usage, os.Args[0]) flag.PrintDefaults() } transpileCommand.SetOutput(stderr) astCommand.SetOutput(stderr) flag.Parse() if *versionFlag { // Simply print out the version and exit. fmt.Println(program.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.Fprintf(stderr, "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.Fprintf(stderr, "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 } c2go-0.26.10/main_test.go000066400000000000000000000354671410601753200150420ustar00rootroot00000000000000// +build integration package main import ( "bytes" "flag" "fmt" "go/format" "go/parser" "go/token" "io/ioutil" "os" "os/exec" "path" "path/filepath" "strconv" "strings" "syscall" "testing" "github.com/elliotchance/c2go/cc" "github.com/elliotchance/c2go/util" ) type programOut struct { stdout bytes.Buffer stderr bytes.Buffer isZero bool } // TestIntegrationScripts tests all programs in the tests directory. // // Integration tests are not run by default (only unit tests). These are // indicated by the build flags at the top of the file. To include integration // tests use: // // go test -tags=integration // // You can also run a single file with: // // go test -tags=integration -run=TestIntegrationScripts/tests/ctype.c // func TestIntegrationScripts(t *testing.T) { testFiles, err := filepath.Glob("tests/*.c") if err != nil { t.Fatal(err) } exampleFiles, err := filepath.Glob("examples/*.c") if err != nil { t.Fatal(err) } files := append(testFiles, exampleFiles...) isVerbose := flag.CommandLine.Lookup("test.v").Value.String() == "true" totalTapTests := 0 var ( buildFolder = "build" cFileName = "a.out" mainFileName = "main.go" stdin = "7" args = []string{"some", "args"} separator = string(os.PathSeparator) ) // Parallel is not acceptable, before solving issue: // https://github.com/elliotchance/c2go/issues/376 // t.Parallel() for _, file := range files { t.Run(file, func(t *testing.T) { cc.ResetCache() cProgram := programOut{} goProgram := programOut{} // create sub folders for test subFolder := buildFolder + separator + strings.Split(file, ".")[0] + separator cPath := subFolder + cFileName // Create build folder err = os.MkdirAll(subFolder, os.ModePerm) if err != nil { t.Fatalf("error: %v", err) } // Compile C. out, err := exec.Command("clang", "-lm", "-o", cPath, file).CombinedOutput() if err != nil { t.Fatalf("error: %s\n%s", err, out) } // Run C program cmd := exec.Command(cPath, args...) cmd.Stdin = strings.NewReader(stdin) cmd.Stdout = &cProgram.stdout cmd.Stderr = &cProgram.stderr err = cmd.Run() cProgram.isZero = err == nil // Check for special exit codes that signal that tests have failed. if exitError, ok := err.(*exec.ExitError); ok { exitStatus := exitError.Sys().(syscall.WaitStatus).ExitStatus() if exitStatus == 101 || exitStatus == 102 { t.Fatal(cProgram.stdout.String()) } } mainFileName = "main_test.go" programArgs := DefaultProgramArgs() programArgs.inputFiles = []string{file} programArgs.outputFile = subFolder + mainFileName // This appends a TestApp function to the output source so we // can run "go test" against the produced binary. programArgs.outputAsTest = true // Compile Go err = Start(programArgs) if err != nil { t.Fatalf("error: %s\n%s", err, out) } // Run Go program. The "-v" option is important; without it most or // all of the fmt.* output would be suppressed. args := []string{ "test", programArgs.outputFile, "-v", } if strings.Index(file, "examples/") == -1 { testName := strings.Split(file, ".")[0][6:] args = append( args, "-race", "-covermode=atomic", "-coverprofile="+testName+".coverprofile", "-coverpkg=./noarch,./linux,./darwin", ) } args = append(args, "--", "some", "args") cmd = exec.Command("go", args...) cmd.Stdin = strings.NewReader("7") cmd.Stdout = &goProgram.stdout cmd.Stderr = &goProgram.stderr err = cmd.Run() goProgram.isZero = err == nil // Check stderr. "go test" will produce warnings when packages are // not referenced as dependencies. We need to strip out these // warnings so it doesn't effect the comparison. cProgramStderr := cProgram.stderr.String() goProgramStderr := goProgram.stderr.String() r := util.GetRegex("warning: no packages being tested depend on .+\n") goProgramStderr = r.ReplaceAllString(goProgramStderr, "") // It is need only for "tests/assert.c" // for change absolute path to local path currentDir, err := os.Getwd() if err != nil { t.Fatal("Cannot get currently dir") } goProgramStderr = strings.Replace(goProgramStderr, currentDir+"/", "", -1) if cProgramStderr != goProgramStderr { // Add addition debug information for lines like: // build/tests/cast/main_test.go:195:1: expected '}', found 'type' buildPrefix := "build/tests/" var output string lines := strings.Split(goProgramStderr, "\n") for _, line := range lines { line = strings.TrimSpace(line) if !strings.HasPrefix(line, buildPrefix) { continue } index := strings.Index(line, ":") if index < 0 { continue } filename := "./" + line[0:index] output += "+========================+\n" output += fmt.Sprintf("File : %s\n\n", filename) if len(line) <= index+1 { continue } line = line[index+1:] index = strings.Index(line, ":") if index < 0 { continue } linePosition, err := strconv.Atoi(line[:index]) if err != nil { err = nil continue } content, err := ioutil.ReadFile(filename) if err != nil { err = nil continue } fileLines := strings.Split(string(content), "\n") start := linePosition - 20 if start < 0 { start = 0 } for i := start; i < linePosition+5 && i < len(fileLines); i++ { output += fmt.Sprintf("Line : %3d : %s\n", i, fileLines[i]) } } t.Fatalf("Expected %s\nGot: %s\nParts of code:\n%s", cProgramStderr, goProgramStderr, output) } // Check stdout cOut := cProgram.stdout.String() goOutLines := strings.Split(goProgram.stdout.String(), "\n") // An out put should look like this: // // === RUN TestApp // 1..3 // 1 ok - argc == 3 + offset // 2 ok - argv[1 + offset] == "some" // 3 ok - argv[2 + offset] == "args" // --- PASS: TestApp (0.03s) // PASS // coverage: 0.0% of statements // ok command-line-arguments 1.050s // // The first line and 4 of the last lines can be ignored as they are // part of the "go test" runner and not part of the program output. // // Note: There is a blank line at the end of the output so when we // say the last line we are really talking about the second last // line. Rather than trimming the whitespace off the C and Go output // we will just make note of the different line index. // // Some tests are designed to fail, like assert.c. In this case the // result output is slightly different: // // === RUN TestApp // 1..0 // 10 // # FAILED: There was 1 failed tests. // exit status 101 // FAIL command-line-arguments 0.041s // // The last three lines need to be removed. // // Before we proceed comparing the raw output we should check that // the header and footer of the output fits one of the two formats // in the examples above. if goOutLines[0] != "=== RUN TestApp" { t.Fatalf("The header of the output cannot be understood:\n%s", strings.Join(goOutLines, "\n")) } if !strings.HasPrefix(goOutLines[len(goOutLines)-2], "ok \tcommand-line-arguments") && !strings.HasPrefix(goOutLines[len(goOutLines)-2], "FAIL\tcommand-line-arguments") { t.Fatalf("The footer of the output cannot be understood:\n%v", strings.Join(goOutLines, "\n")) } // A failure will cause (always?) "go test" to output the exit code // before the final line. We should also ignore this as its not part // of our output. // // There is a separate check to see that both the C and Go programs // return the same exit code. removeLinesFromEnd := 5 if strings.Index(file, "examples/") >= 0 { removeLinesFromEnd = 4 } else if strings.HasPrefix(goOutLines[len(goOutLines)-3], "exit status") { removeLinesFromEnd = 3 } var goOut string if len(goOutLines)-removeLinesFromEnd < 1 { goOut = "\n" } else { goOut = strings.Join(goOutLines[1:len(goOutLines)-removeLinesFromEnd], "\n") + "\n" } // Check if both exit codes are zero (or non-zero) if cProgram.isZero != goProgram.isZero { t.Fatalf("Exit statuses did not match.\n%s", util.ShowDiff(cOut, goOut)) } if cOut != goOut { t.Fatalf(util.ShowDiff(cOut, goOut)) } // If this is not an example we will extract the number of tests // run. if strings.Index(file, "examples/") == -1 && isVerbose { firstLine := strings.Split(goOut, "\n")[0] matches := util.GetRegex(`1\.\.(\d+)`). FindStringSubmatch(firstLine) if len(matches) == 0 { t.Fatalf("Test did not output tap: %s, got:\n%s", file, goProgram.stdout.String()) } fmt.Printf("TAP: # %s: %s tests\n", file, matches[1]) totalTapTests += util.Atoi(matches[1]) } }) } if isVerbose { fmt.Printf("TAP: # Total tests: %d\n", totalTapTests) } } func TestStartPreprocess(t *testing.T) { // create temp file with guarantee // wrong file body dir, err := ioutil.TempDir("", "c2go-preprocess") if err != nil { t.Fatalf("Cannot create temp folder: %v", err) } defer os.RemoveAll(dir) // clean up name := "preprocess.c" filename := path.Join(dir, name) body := ([]byte)("#include \nint main(void){\nwrong();\n}") err = ioutil.WriteFile(filename, body, 0644) args := DefaultProgramArgs() args.inputFiles = []string{dir + name} err = Start(args) if err == nil { t.Fatalf("Cannot test preprocess of application") } } func TestMultiFileTranspilation(t *testing.T) { tcs := []struct { source []string expectedOutput string }{ { []string{ "./tests/multi/main1.c", "./tests/multi/main2.c", }, "234ERROR!ERROR!ERROR!", }, { []string{ "./tests/multi-struct/main.c", "./tests/multi-struct/types.c", }, "42\n", }, } for pos, tc := range tcs { t.Run(fmt.Sprintf("Test %d", pos), func(t *testing.T) { var args = DefaultProgramArgs() args.inputFiles = tc.source dir, err := ioutil.TempDir("", "c2go_multi") if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) // clean up args.outputFile = path.Join(dir, "multi.go") args.packageName = "main" args.outputAsTest = true // testing err = Start(args) if err != nil { t.Errorf(err.Error()) } // Run Go program var buf bytes.Buffer cmd := exec.Command("go", "run", args.outputFile) cmd.Stdout = &buf cmd.Stderr = &buf err = cmd.Run() if err != nil { t.Errorf(err.Error()) } if buf.String() != tc.expectedOutput { t.Errorf("Wrong result: %v", buf.String()) } }) } } func TestTriGraph(t *testing.T) { var args = DefaultProgramArgs() args.inputFiles = []string{"./tests/trigraph/main.c"} dir, err := ioutil.TempDir("", "c2go_trigraph") if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) // clean up args.outputFile = path.Join(dir, "multi.go") args.clangFlags = []string{"-trigraphs"} args.packageName = "main" args.outputAsTest = true // testing err = Start(args) if err != nil { t.Errorf(err.Error()) } // Run Go program var buf bytes.Buffer cmd := exec.Command("go", "run", args.outputFile) cmd.Stdout = &buf cmd.Stderr = &buf err = cmd.Run() if err != nil { t.Errorf(err.Error()) } if buf.String() != "#" { t.Errorf("Wrong result: %v", buf.String()) } } func TestExternalInclude(t *testing.T) { var args = DefaultProgramArgs() args.inputFiles = []string{"./tests/externalHeader/main/main.c"} dir, err := ioutil.TempDir("", "c2go_multi4") if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) // clean up args.outputFile = path.Join(dir, "multi.go") args.clangFlags = []string{"-I./tests/externalHeader/include/"} args.packageName = "main" args.outputAsTest = true // testing err = Start(args) if err != nil { t.Errorf(err.Error()) } // Run Go program var buf bytes.Buffer cmd := exec.Command("go", "run", args.outputFile) cmd.Stdout = &buf cmd.Stderr = &buf err = cmd.Run() if err != nil { t.Errorf(err.Error()) } if buf.String() != "42" { t.Errorf("Wrong result: %v", buf.String()) } } func TestComments(t *testing.T) { var args = DefaultProgramArgs() args.inputFiles = []string{"./tests/comment/main.c"} dir := "./build/comment" _ = os.Mkdir(dir, os.ModePerm) args.outputFile = path.Join(dir, "comment.go") args.packageName = "main" args.outputAsTest = true // testing err := Start(args) if err != nil { t.Errorf(err.Error()) } dat, err := ioutil.ReadFile(args.outputFile) if err != nil { t.Errorf(err.Error()) } reg := util.GetRegex("comment(\\d+)") comms := reg.FindAll(dat, -1) amountComments := 30 for i := range comms { if fmt.Sprintf("comment%d", i+1) != string(comms[i]) { t.Fatalf("Not expected name of comment.Expected = %s, actual = %s.", fmt.Sprintf("comment%d", i+1), string(comms[i])) } } if len(comms) != amountComments { t.Fatalf("Expect %d comments, but found %d commnets", amountComments, len(comms)) } } func TestCodeQuality(t *testing.T) { files, err := filepath.Glob("tests/code_quality/*.c") if err != nil { t.Fatal(err) } // Parallel is not acceptable, before solving issue: // https://github.com/elliotchance/c2go/issues/376 // t.Parallel() suffix := ".expected.c" for i, file := range files { if strings.HasSuffix(file, suffix) { continue } t.Run(file, func(t *testing.T) { dir, err := ioutil.TempDir("", fmt.Sprintf("c2go_code_quality_%d_", i)) if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) // clean up var args = DefaultProgramArgs() args.inputFiles = []string{file} args.outputFile = path.Join(dir, "main.go") args.packageName = "code_quality" args.outputAsTest = false // testing err = Start(args) if err != nil { t.Fatalf(err.Error()) } goActual, err := cleaningGoCode(args.outputFile) if err != nil { t.Fatalf(err.Error()) } goExpect, err := cleaningGoCode(file[:len(file)-2] + suffix) if err != nil { t.Fatalf(err.Error()) } if bytes.Compare(goActual, goExpect) != 0 { fmt.Println("actual : ", string(goActual)) fmt.Println("expected : ", string(goExpect)) t.Errorf("Code quality error for : %s", file) } }) } } func cleaningGoCode(fileName string) (dat []byte, err error) { // read file dat, err = ioutil.ReadFile(fileName) if err != nil { return } // remove comments fset := token.NewFileSet() // positions are relative to fset f, err := parser.ParseFile(fset, "", string(dat), 0) if err != nil { return } var buf bytes.Buffer err = format.Node(&buf, fset, f) if err != nil { return } // remove all spaces and tabs dat = bytes.Replace(buf.Bytes(), []byte{' '}, []byte{}, -1) dat = bytes.Replace(dat, []byte{'\n'}, []byte{}, -1) dat = bytes.Replace(dat, []byte{'\t'}, []byte{}, -1) dat = bytes.Replace(dat, []byte{'\r'}, []byte{}, -1) return } c2go-0.26.10/noarch/000077500000000000000000000000001410601753200137635ustar00rootroot00000000000000c2go-0.26.10/noarch/errno.go000066400000000000000000000261651410601753200154510ustar00rootroot00000000000000package noarch import ( "strings" ) const ( EPERM = 1 // Operation not permitted ENOENT = 2 // No such file or directory ESRCH = 3 // No such process EINTR = 4 // Interrupted system call EIO = 5 // I/O error ENXIO = 6 // No such device or address E2BIG = 7 // Argument list too long ENOEXEC = 8 // Exec format error EBADF = 9 // Bad file number ECHILD = 10 // No child processes EAGAIN = 11 // Try again ENOMEM = 12 // Out of memory EACCES = 13 // Permission denied EFAULT = 14 // Bad address ENOTBLK = 15 // Block device required EBUSY = 16 // Device or resource busy EEXIST = 17 // File exists EXDEV = 18 // Cross-device link ENODEV = 19 // No such device ENOTDIR = 20 // Not a directory EISDIR = 21 // Is a directory EINVAL = 22 // Invalid argument ENFILE = 23 // File table overflow EMFILE = 24 // Too many open files ENOTTY = 25 // Not a typewriter ETXTBSY = 26 // Text file busy EFBIG = 27 // File too large ENOSPC = 28 // No space left on device ESPIPE = 29 // Illegal seek EROFS = 30 // Read-only file system EMLINK = 31 // Too many links EPIPE = 32 // Broken pipe EDOM = 33 // Math argument out of domain of func ERANGE = 34 // Math result not representable EDEADLK = 35 // Resource deadlock would occur ENAMETOOLONG = 36 // File name too long ENOLCK = 37 // No record locks available ENOSYS = 38 // Function not implemented ENOTEMPTY = 39 // Directory not empty ELOOP = 40 // Too many symbolic links encountered EWOULDBLOCK = EAGAIN // Operation would block ENOMSG = 42 // No message of desired type EIDRM = 43 // Identifier removed ECHRNG = 44 // Channel number out of range EL2NSYNC = 45 // Level 2 not synchronized EL3HLT = 46 // Level 3 halted EL3RST = 47 // Level 3 reset ELNRNG = 48 // Link number out of range EUNATCH = 49 // Protocol driver not attached ENOCSI = 50 // No CSI structure available EL2HLT = 51 // Level 2 halted EBADE = 52 // Invalid exchange EBADR = 53 // Invalid request descriptor EXFULL = 54 // Exchange full ENOANO = 55 // No anode EBADRQC = 56 // Invalid request code EBADSLT = 57 // Invalid slot EDEADLOCK = EDEADLK EBFONT = 59 // Bad font file format ENOSTR = 60 // Device not a stream ENODATA = 61 // No data available ETIME = 62 // Timer expired ENOSR = 63 // Out of streams resources ENONET = 64 // Machine is not on the network ENOPKG = 65 // Package not installed EREMOTE = 66 // Object is remote ENOLINK = 67 // Link has been severed EADV = 68 // Advertise error ESRMNT = 69 // Srmount error ECOMM = 70 // Communication error on send EPROTO = 71 // Protocol error EMULTIHOP = 72 // Multihop attempted EDOTDOT = 73 // RFS specific error EBADMSG = 74 // Not a data message EOVERFLOW = 75 // Value too large for defined data type ENOTUNIQ = 76 // Name not unique on network EBADFD = 77 // File descriptor in bad state EREMCHG = 78 // Remote address changed ELIBACC = 79 // Can not access a needed shared library ELIBBAD = 80 // Accessing a corrupted shared library ELIBSCN = 81 // .lib section in a.out corrupted ELIBMAX = 82 // Attempting to link in too many shared libraries ELIBEXEC = 83 // Cannot exec a shared library directly EILSEQ = 84 // Illegal byte sequence ERESTART = 85 // Interrupted system call should be restarted ESTRPIPE = 86 // Streams pipe error EUSERS = 87 // Too many users ENOTSOCK = 88 // Socket operation on non-socket EDESTADDRREQ = 89 // Destination address required EMSGSIZE = 90 // Message too long EPROTOTYPE = 91 // Protocol wrong type for socket ENOPROTOOPT = 92 // Protocol not available EPROTONOSUPPORT = 93 // Protocol not supported ESOCKTNOSUPPORT = 94 // Socket type not supported EOPNOTSUPP = 95 // Operation not supported on transport endpoint EPFNOSUPPORT = 96 // Protocol family not supported EAFNOSUPPORT = 97 // Address family not supported by protocol EADDRINUSE = 98 // Address already in use EADDRNOTAVAIL = 99 // Cannot assign requested address ENETDOWN = 100 // Network is down ENETUNREACH = 101 // Network is unreachable ENETRESET = 102 // Network dropped connection because of reset ECONNABORTED = 103 // Software caused connection abort ECONNRESET = 104 // Connection reset by peer ENOBUFS = 105 // No buffer space available EISCONN = 106 // Transport endpoint is already connected ENOTCONN = 107 // Transport endpoint is not connected ESHUTDOWN = 108 // Cannot send after transport endpoint shutdown ETOOMANYREFS = 109 // Too many references: cannot splice ETIMEDOUT = 110 // Connection timed out ECONNREFUSED = 111 // Connection refused EHOSTDOWN = 112 // Host is down EHOSTUNREACH = 113 // No route to host EALREADY = 114 // Operation already in progress EINPROGRESS = 115 // Operation now in progress ESTALE = 116 // Stale NFS file handle EUCLEAN = 117 // Structure needs cleaning ENOTNAM = 118 // Not a XENIX named type file ENAVAIL = 119 // No XENIX semaphores available EISNAM = 120 // Is a named type file EREMOTEIO = 121 // Remote I/O error EDQUOT = 122 // Quota exceeded ENOMEDIUM = 123 // No medium found EMEDIUMTYPE = 124 // Wrong medium type ECANCELED = 125 // Operation Canceled ENOKEY = 126 // Required key not available EKEYEXPIRED = 127 // Key has expired EKEYREVOKED = 128 // Key has been revoked EKEYREJECTED = 129 // Key was rejected by service // for robust mutexes EOWNERDEAD = 130 // Owner died ENOTRECOVERABLE = 131 // State not recoverable ) // Error table var errors = [...]string{ 1: "operation not permitted", 2: "no such file or directory", 3: "no such process", 4: "interrupted system call", 5: "input/output error", 6: "no such device or address", 7: "argument list too long", 8: "exec format error", 9: "bad file descriptor", 10: "no child processes", 11: "resource temporarily unavailable", 12: "cannot allocate memory", 13: "permission denied", 14: "bad address", 15: "block device required", 16: "device or resource busy", 17: "file exists", 18: "invalid cross-device link", 19: "no such device", 20: "not a directory", 21: "is a directory", 22: "invalid argument", 23: "too many open files in system", 24: "too many open files", 25: "inappropriate ioctl for device", 26: "text file busy", 27: "file too large", 28: "no space left on device", 29: "illegal seek", 30: "read-only file system", 31: "too many links", 32: "broken pipe", 33: "numerical argument out of domain", 34: "numerical result out of range", 35: "resource deadlock avoided", 36: "file name too long", 37: "no locks available", 38: "function not implemented", 39: "directory not empty", 40: "too many levels of symbolic links", 42: "no message of desired type", 43: "identifier removed", 44: "channel number out of range", 45: "level 2 not synchronized", 46: "level 3 halted", 47: "level 3 reset", 48: "link number out of range", 49: "protocol driver not attached", 50: "no CSI structure available", 51: "level 2 halted", 52: "invalid exchange", 53: "invalid request descriptor", 54: "exchange full", 55: "no anode", 56: "invalid request code", 57: "invalid slot", 59: "bad font file format", 60: "device not a stream", 61: "no data available", 62: "timer expired", 63: "out of streams resources", 64: "machine is not on the network", 65: "package not installed", 66: "object is remote", 67: "link has been severed", 68: "advertise error", 69: "srmount error", 70: "communication error on send", 71: "protocol error", 72: "multihop attempted", 73: "RFS specific error", 74: "bad message", 75: "value too large for defined data type", 76: "name not unique on network", 77: "file descriptor in bad state", 78: "remote address changed", 79: "can not access a needed shared library", 80: "accessing a corrupted shared library", 81: ".lib section in a.out corrupted", 82: "attempting to link in too many shared libraries", 83: "cannot exec a shared library directly", 84: "invalid or incomplete multibyte or wide character", 85: "interrupted system call should be restarted", 86: "streams pipe error", 87: "too many users", 88: "socket operation on non-socket", 89: "destination address required", 90: "message too long", 91: "protocol wrong type for socket", 92: "protocol not available", 93: "protocol not supported", 94: "socket type not supported", 95: "operation not supported", 96: "protocol family not supported", 97: "address family not supported by protocol", 98: "address already in use", 99: "cannot assign requested address", 100: "network is down", 101: "network is unreachable", 102: "network dropped connection on reset", 103: "software caused connection abort", 104: "connection reset by peer", 105: "no buffer space available", 106: "transport endpoint is already connected", 107: "transport endpoint is not connected", 108: "cannot send after transport endpoint shutdown", 109: "too many references: cannot splice", 110: "connection timed out", 111: "connection refused", 112: "host is down", 113: "no route to host", 114: "operation already in progress", 115: "operation now in progress", 116: "stale NFS file handle", 117: "structure needs cleaning", 118: "not a XENIX named type file", 119: "no XENIX semaphores available", 120: "is a named type file", 121: "remote I/O error", 122: "disk quota exceeded", 123: "no medium found", 124: "wrong medium type", 125: "operation canceled", 126: "required key not available", 127: "key has expired", 128: "key has been revoked", 129: "key was rejected by service", 130: "owner died", 131: "state not recoverable", 132: "operation not possible due to RF-kill", } var err2bytes = make(map[int][]byte) var errInverse = make(map[string]int) func init() { err2bytes[0] = []byte{0} for i, str := range errors { err2bytes[i] = []byte(str) err2bytes[i] = append(err2bytes[i], 0) err2bytes[i][0] = strings.ToUpper(string(err2bytes[i][0:1]))[0] errInverse[strings.ToLower(str)] = i } } // Strerror translates an errno error code into an error message. func Strerror(errno int32) *byte { b, ok := err2bytes[int(errno)] if ok { return &b[0] } return &err2bytes[0][0] } var currentErrno int32 func setCurrentErrnoErr(err error) { if err == nil { currentErrno = 0 } else { errStr := strings.ToLower(err.Error()) if i, ok := errInverse[errStr]; ok { currentErrno = int32(i) } else { currentErrno = ENODATA } } } func setCurrentErrno(errno int32) { currentErrno = errno } // Errno returns a pointer to the current errno. func Errno() *int32 { return ¤tErrno } c2go-0.26.10/noarch/math.go000066400000000000000000000007521410601753200152470ustar00rootroot00000000000000package noarch import ( "math" ) func Signbitf(x float32) int32 { return BoolToInt(math.Signbit(float64(x))) } func Signbitd(x float64) int32 { return BoolToInt(math.Signbit(x)) } func Signbitl(x float64) int32 { return BoolToInt(math.Signbit(x)) } func IsNaN(x float64) int32 { return BoolToInt(math.IsNaN(x)) } // Ldexp is the inverse of Frexp. // Ldexp uses math.Ldexp to calculate the value. func Ldexp(frac float64, exp int32) float64 { return math.Ldexp(frac, int(exp)) } c2go-0.26.10/noarch/noarch.go000066400000000000000000000025341410601753200155700ustar00rootroot00000000000000// Package noarch contains low-level functions that apply to multiple platforms. package noarch // BoolToInt converts boolean value to an int, which is a common operation in C. // 0 and 1 represent false and true respectively. func BoolToInt(x bool) int32 { if x { return 1 } return 0 } // NotInt performs a logical not (!) on an integer and returns an integer. func NotInt(x int) int { if x == 0 { return 1 } return 0 } // NotInt32 works the same as NotInt, but on a int32. func NotInt32(x int32) int32 { if x == 0 { return 1 } return 0 } // NotUint16 works the same as NotInt, but on a uint16. func NotUint16(x uint16) uint16 { if x == 0 { return 1 } return 0 } // NotUint32 works the same as NotInt, but on a uint32. func NotUint32(x uint32) uint32 { if x == 0 { return 1 } return 0 } // NotInt8 works the same as NotInt, but on a int8. func NotInt8(x int8) int8 { if x == 0 { return 1 } return 0 } // Ternary simulates the ternary (also known as the conditional operator). Go // does not have the equivalent of using if statements as expressions or inline // if statements. This function takes the true and false parts as closures to be // sure that only the true or false condition is evaulated - to prevent side // effects. func Ternary(a bool, b, c func() interface{}) interface{} { if a { return b() } return c() } c2go-0.26.10/noarch/stdarg.go000066400000000000000000000001051410601753200155720ustar00rootroot00000000000000package noarch type VaList struct { Pos int Args []interface{} } c2go-0.26.10/noarch/stdio.go000066400000000000000000000701261410601753200154420ustar00rootroot00000000000000package noarch import ( "fmt" "io" "io/ioutil" "os" "reflect" "strings" "unsafe" ) // Programs generated by c2go will reference noarch.Stdin instead of os.Stdin // directly so that under test these can be replaced. This is required because // "go test" does not redirect the stdin to the executable it is testing. var ( Stdin = NewFile(os.Stdin) Stdout = NewFile(os.Stdout) Stderr = NewFile(os.Stderr) ) // File represents the definition has been translated from the original // definition for __sFILE, which is an alias for FILE. Not all of the attributes // have been translated. They should be turned on as needed. type File struct { // This is not part of the original struct but it is needed for internal // calls in Go. OsFile *os.File // unsigned char *_p; // int _r; // int _w; // short _flags; // short _file; // struct __sbuf _bf; // int _lbfsize; // void *_cookie; // int (* _Nullable _close)(void *); // int (* _Nullable _read) (void *, char *, int); // fpos_t (* _Nullable _seek) (void *, fpos_t, int); // int (* _Nullable _write)(void *, const char *, int); // struct __sbuf _ub; // struct __sFILEX *_extra; // int _ur; // unsigned char _ubuf[3]; // unsigned char _nbuf[1]; // struct __sbuf _lb; // int _blksize; // fpos_t _offset; _flags int32 } // Fopen handles fopen(). // // Opens the file whose name is specified in the parameter filePath and // associates it with a stream that can be identified in future operations by // the File pointer returned. // // The operations that are allowed on the stream and how these are performed are // defined by the mode parameter. // // The returned pointer can be disassociated from the file by calling fclose() // or freopen(). All opened files are automatically closed on normal program // termination. func Fopen(filePath, mode *byte) *File { var file *os.File var err error sFilePath := CStringToString(filePath) var fileExists bool var info os.FileInfo info, err = os.Stat(sFilePath) if info != nil || !os.IsNotExist(err) { fileExists = true } m := CStringToString(mode) // no-overwrite flag if strings.Contains(m, "x") { m = strings.Replace(m, "x", "", -1) if strings.Contains(m, "w") && fileExists { // only applies when writing to a file setCurrentErrno(EEXIST) return nil } } // binary flag if strings.Contains(m, "b") { m = strings.Replace(m, "b", "", -1) // no other action needed, we are always using binary mode } var flags int32 switch m { case "r": flags |= io_NO_WRITES file, err = os.OpenFile(sFilePath, os.O_RDONLY, 0655) case "r+": file, err = os.OpenFile(sFilePath, os.O_RDWR, 0655) case "a": flags |= io_NO_READS file, err = os.OpenFile(sFilePath, os.O_WRONLY|os.O_APPEND, 0655) case "a+": file, err = os.OpenFile(sFilePath, os.O_RDWR|os.O_APPEND, 0655) case "w": file, err = os.OpenFile(sFilePath, os.O_RDWR|os.O_CREATE, 0655) if err == nil && fileExists { err = file.Truncate(0) } case "w+": file, err = os.OpenFile(sFilePath, os.O_RDWR|os.O_CREATE, 0655) if err == nil && fileExists { err = file.Truncate(0) } default: panic(fmt.Sprintf("unsupported file mode: %s", m)) } if err != nil { setFopenErrno(err) return nil } nf := NewFile(file) nf._flags |= flags return nf } func setFopenErrno(err error) { pe := err.(*os.PathError) setCurrentErrnoErr(pe.Err) } // Fclose handles fclose(). // // Closes the file associated with the stream and disassociates it. // // All internal buffers associated with the stream are disassociated from it and // flushed: the content of any unwritten output buffer is written and the // content of any unread input buffer is discarded. // // Even if the call fails, the stream passed as parameter will no longer be // associated with the file nor its buffers. func Fclose(f *File) int32 { err := f.OsFile.Close() if err != nil { if err == os.ErrInvalid { setCurrentErrno(EINVAL) } else if pe, ok := err.(*os.PathError); ok { setCurrentErrnoErr(pe.Err) } else { setCurrentErrnoErr(err) } return EOF } return 0 } // Remove handles remove(). // // Deletes the file whose name is specified in filePath. // // This is an operation performed directly on a file identified by its filePath; // No streams are involved in the operation. // // Proper file access shall be available. func Remove(filePath *byte) int32 { if os.Remove(CStringToString(filePath)) != nil { return -1 } return 0 } // Rename handles rename(). // // Changes the name of the file or directory specified by oldName to newName. // // This is an operation performed directly on a file; No streams are involved in // the operation. // // If oldName and newName specify different paths and this is supported by the // system, the file is moved to the new location. // // If newName names an existing file, the function may either fail or override // the existing file, depending on the specific system and library // implementation. // // Proper file access shall be available. func Rename(oldName, newName *byte) int32 { from := CStringToString(oldName) to := CStringToString(newName) if os.Rename(from, to) != nil { return -1 } return 0 } // Fputs handles fputs(). // // Writes the C string pointed by str to the stream. // // The function begins copying from the address specified (str) until it reaches // the terminating null character ('\0'). This terminating null-character is not // copied to the stream. // // Notice that fputs not only differs from puts in that the destination stream // can be specified, but also fputs does not write additional characters, while // puts appends a newline character at the end automatically. func Fputs(str *byte, stream *File) int32 { goStr := CStringToString(str) n, err := stream.OsFile.WriteString(goStr) if err != nil { panic(err) } return int32(n) } // Tmpfile handles tmpfile(). // // Creates a temporary binary file, open for update ("wb+" mode, see fopen for // details) with a filename guaranteed to be different from any other existing // file. // // The temporary file created is automatically deleted when the stream is closed // (fclose) or when the program terminates normally. If the program terminates // abnormally, whether the file is deleted depends on the specific system and // library implementation. func Tmpfile() *File { f, err := ioutil.TempFile("", "") if err != nil { return nil } return NewFile(f) } // Fgets handles fgets(). // // Reads characters from stream and stores them as a C string into str until // (num-1) characters have been read or either a newline or the end-of-file is // reached, whichever happens first. // // A newline character makes fgets stop reading, but it is considered a valid // character by the function and included in the string copied to str. // // A terminating null character is automatically appended after the characters // copied to str. // // Notice that fgets is quite different from gets: not only fgets accepts a // stream argument, but also allows to specify the maximum size of str and // includes in the string any ending newline character. func Fgets(str *byte, num int32, stream *File) *byte { buf := make([]byte, num) n, err := stream.OsFile.Read(buf[:num-1]) var newlinepos int for ; newlinepos < n-1; newlinepos++ { if buf[newlinepos] == '\n' { break } } buf[newlinepos+1] = 0 if newlinepos < n-1 { stream.OsFile.Seek(int64(newlinepos-n+1), 1) } if err != nil { if n == 0 && err == io.EOF { stream._flags |= io_EOF_SEEN } else { stream._flags |= io_ERR_SEEN } return nil } copy(toByteSlice(str, num), buf[:newlinepos+2]) return str } // Clearerr handles clearerr(). // // Resets both the error and the eof indicators of the stream. // // When a i/o function fails either because of an error or because the end of // the file has been reached, one of these internal indicators may be set for // the stream. The state of these indicators is cleared by a call to this // function, or by a call to any of: rewind, fseek, fsetpos and freopen. func Clearerr(stream *File) { stream._flags &= ^io_EOF_SEEN stream._flags &= ^io_ERR_SEEN } // Rewind handles rewind(). // // Sets the position indicator associated with stream to the beginning of the // file. // // The end-of-file and error internal indicators associated to the stream are // cleared after a successful call to this function, and all effects from // previous calls to ungetc on this stream are dropped. // // On streams open for update (read+write), a call to rewind allows to switch // between reading and writing. func Rewind(stream *File) { Fseek(stream, 0, 0) } // Feof handles feof(). // // Checks whether the end-of-File indicator associated with stream is set, // returning a value different from zero if it is. // // This indicator is generally set by a previous operation on the stream that // attempted to read at or past the end-of-file. // // Notice that stream's internal position indicator may point to the end-of-file // for the next operation, but still, the end-of-file indicator may not be set // until an operation attempts to read at that point. // // This indicator is cleared by a call to clearerr, rewind, fseek, fsetpos or // freopen. Although if the position indicator is not repositioned by such a // call, the next i/o operation is likely to set the indicator again. func Feof(stream *File) int32 { if stream._flags&io_EOF_SEEN != 0 { return 1 } return int32(0) } // Ferror handles ferror(). // // Checks if the error indicator associated with stream is set, // returning a value different from zero if it is. // // This indicator is generally set by a previous operation on the stream that // failed, and is cleared by a call to clearerr, rewind or freopen. func Ferror(stream *File) int32 { if stream._flags&io_ERR_SEEN != 0 { return 1 } return int32(0) } const ( // constants for the File flags io_MAGIC = 0x7BAD0000 // Magic number io_MAGIC_MASK = 0xFFFF0000 io_USER_BUF = 1 // User owns buffer; don't delete it on close. io_UNBUFFERED = 2 io_NO_READS = 4 // Reading not allowed io_NO_WRITES = 8 // Writing not allowed io_EOF_SEEN = 0x10 io_ERR_SEEN = 0x20 io_DELETE_DONT_CLOSE = 0x40 // Don't call close(_fileno) on cleanup. io_LINKED = 0x80 // Set if linked (using _chain) to streambuf::_list_all. io_IN_BACKUP = 0x100 io_LINE_BUF = 0x200 io_TIED_PUT_GET = 0x400 // Set if put and get pointer logicly tied. io_CURRENTLY_PUTTING = 0x800 io_IS_APPENDING = 0x1000 io_IS_FILEBUF = 0x2000 io_BAD_SEEN = 0x4000 io_USER_LOCK = 0x8000 ) // NewFile creates a File pointer from a Go file pointer. func NewFile(f *os.File) *File { return &File{ OsFile: f, _flags: io_MAGIC, } } // Tmpnam handles tmpnam(). // // Returns a string containing a file name different from the name of any // existing file, and thus suitable to safely create a temporary file without // risking to overwrite an existing file. // // If str is a null pointer, the resulting string is stored in an internal // static array that can be accessed by the return value. The content of this // string is preserved at least until a subsequent call to this same function, // which may overwrite it. // // If str is not a null pointer, it shall point to an array of at least L_tmpnam // characters that will be filled with the proposed temporary file name. // // The file name returned by this function can be used to create a regular file // using fopen to be used as a temporary file. The file created this way, unlike // those created with tmpfile is not automatically deleted when closed; A // program shall call remove to delete this file once closed. func Tmpnam(str *byte) *byte { // TODO: There must be a better way of doing this. This way allows the same // great distinct Go temp file generation (that also checks for existing // files), but unfortunately creates the file in the process; even if you // don't intend to use it. f, err := ioutil.TempFile("", "") if err != nil { return nil } f.Close() if str != nil { pStr := toByteSlice(str, int32(len(f.Name()))+1) copy(pStr, f.Name()) pStr[len(f.Name())] = 0 } return &[]byte(f.Name() + "\x00")[0] } // Fflush handles fflush(). // // If the given stream was open for writing (or if it was open for updating and // the last i/o operation was an output operation) any unwritten data in its // output buffer is written to the file. // // If stream is a null pointer, all such streams should be flushed, but this is // currently not supported. // // The stream remains open after this call. // // When a file is closed, either because of a call to fclose or because the // program terminates, all the buffers associated with it are automatically // flushed. func Fflush(stream *File) int32 { err := stream.OsFile.Sync() if err != nil { return 1 } return 0 } // Fprintf handles fprintf(). // // Writes the C string pointed by format to the stream. If format includes // format specifiers (subsequences beginning with %), the additional arguments // following format are formatted and inserted in the resulting string replacing // their respective specifiers. // // After the format parameter, the function expects at least as many additional // arguments as specified by format. func Fprintf(f *File, format *byte, args ...interface{}) int32 { realArgs := []interface{}{} // Convert any C strings into Go strings. typeOfByteSlice := reflect.TypeOf((*byte)(nil)) for _, arg := range args { if reflect.TypeOf(arg) == typeOfByteSlice { realArgs = append(realArgs, CStringToString(arg.(*byte))) } else { realArgs = append(realArgs, arg) } } n, err := fmt.Fprintf(f.OsFile, CStringToString(format), realArgs...) if err != nil { return -1 } return int32(n) } // Fscanf handles fscanf(). // // Reads data from the stream and stores them according to the parameter format // into the locations pointed by the additional arguments. // // The additional arguments should point to already allocated objects of the // type specified by their corresponding format specifier within the format // string. func Fscanf(f *File, format *byte, args ...interface{}) int32 { realArgs := prepareArgsForScanf(args) // format is ignored // See https://github.com/elliotchance/c2go/issues/607 _ = format n, err := fmt.Fscan(f.OsFile, realArgs...) if err != nil { f._flags |= io_EOF_SEEN return EOF } finalizeArgsForScanf(realArgs, args) return int32(n) } func finalizeArgsForScanf(realArgs []interface{}, args []interface{}) { typeOfStringRef := reflect.TypeOf(new(string)) for i, arg := range realArgs { if reflect.TypeOf(arg) == typeOfStringRef { s := *arg.(*string) byteSlice := toByteSlice(args[i].(*byte), int32(len(s)+1)) copy(byteSlice, []byte(s)) byteSlice[len(s)] = 0 } } } func prepareArgsForScanf(args []interface{}) []interface{} { realArgs := []interface{}{} typeOfBytePointer := reflect.TypeOf((*byte)(nil)) for _, arg := range args { if reflect.TypeOf(arg) == typeOfBytePointer { realArgs = append(realArgs, new(string)) } else { realArgs = append(realArgs, arg) } } return realArgs } const EOF = -int32(1) func getc(f *os.File) int32 { buffer := make([]byte, 1) _, err := f.Read(buffer) if err != nil { return EOF } return int32(buffer[0]) } // Fgetc handles fgetc(). // // Returns the character currently pointed by the internal file position // indicator of the specified stream. The internal file position indicator is // then advanced to the next character. // // If the stream is at the end-of-file when called, the function returns EOF and // sets the end-of-file indicator for the stream (feof). // // If a read error occurs, the function returns EOF and sets the error indicator // for the stream (ferror). // // fgetc and getc are equivalent, except that getc may be implemented as a macro // in some libraries. func Fgetc(stream *File) (ret int32) { ret = getc(stream.OsFile) if ret == EOF { stream._flags |= io_EOF_SEEN } return } // Fputc handles fputc(). // // Writes a character to the stream and advances the position indicator. // // The character is written at the position indicated by the internal position // indicator of the stream, which is then automatically advanced by one. func Fputc(c int32, f *File) int32 { n, err := f.OsFile.Write([]byte{byte(c)}) if err != nil { return 0 } return int32(n) } // Getchar handles getchar(). // // Returns the next character from the standard input (stdin). // // It is equivalent to calling getc with stdin as argument. func Getchar() int32 { return getc(Stdin.OsFile) } // Fseek handles fseek(). // // Sets the position indicator associated with the stream to a new position. // // For streams open in binary mode, the new position is defined by adding offset // to a reference position specified by origin. // // For streams open in text mode, offset shall either be zero or a value // returned by a previous call to ftell, and origin shall necessarily be // SEEK_SET. // // If the function is called with other values for these arguments, support // depends on the particular system and library implementation (non-portable). // // The end-of-file internal indicator of the stream is cleared after a // successful call to this function, and all effects from previous calls to // ungetc on this stream are dropped. // // On streams open for update (read+write), a call to fseek allows to switch // between reading and writing. func Fseek(f *File, offset int32, origin int32) int32 { n, err := f.OsFile.Seek(int64(offset), int(origin)) if err != nil { f._flags |= io_EOF_SEEN return EOF } Clearerr(f) return int32(n) } // Ftell handles ftell(). // // Returns the current value of the position indicator of the stream. // // For binary streams, this is the number of bytes from the beginning of the // file. // // For text streams, the numerical value may not be meaningful but can still be // used to restore the position to the same position later using fseek (if there // are characters put back using ungetc still pending of being read, the // behavior is undefined). func Ftell(f *File) int32 { return int32(Fseek(f, 0, 1)) } // Fread handles fread(). // // Reads an array of count elements, each one with a size of size bytes, from // the stream and stores them in the block of memory specified by ptr. // // The position indicator of the stream is advanced by the total amount of bytes // read. // // The total amount of bytes read if successful is (size*count). func Fread(ptr unsafe.Pointer, size1, size2 int32, f *File) int32 { // Create a new buffer so that we can ensure we read up to the correct // number of bytes from the file. newBuffer := make([]byte, size1*size2) ptrSlice := toByteSlice((*byte)(ptr), size1*size2) n, err := f.OsFile.Read(newBuffer) // Despite any error we need to make sure the bytes read are copied to the // destination buffer. for i, b := range newBuffer { ptrSlice[i] = b } // Now we can handle the success or failure. if err != nil { if err == io.EOF { f._flags |= io_EOF_SEEN } else { f._flags |= io_ERR_SEEN } return EOF } return int32(n) } // Fwrite handles fwrite(). // // Writes an array of count elements, each one with a size of size bytes, from // the block of memory pointed by ptr to the current position in the stream. // // The position indicator of the stream is advanced by the total number of bytes // written. // // Internally, the function interprets the block pointed by ptr as if it was an // array of (size*count) elements of type unsigned char, and writes them // sequentially to stream as if fputc was called for each byte. func Fwrite(str *byte, size1, size2 int32, stream *File) int32 { n, err := stream.OsFile.Write(toByteSlice(str, size1*size2)) if err != nil { return -1 } return int32(n) } // Fgetpos handles fgetpos(). // // Retrieves the current position in the stream. // // The function fills the fpos_t object pointed by pos with the information // needed from the stream's position indicator to restore the stream to its // current position (and multibyte state, if wide-oriented) with a call to // fsetpos. // // The ftell function can be used to retrieve the current position in the stream //as an integer value. func Fgetpos(f *File, pos *int32) int32 { absolutePos := Fseek(f, 0, 1) if pos != nil { *pos = absolutePos } return absolutePos } // Fsetpos handles fsetpos(). // // Restores the current position in the stream to pos. // // The internal file position indicator associated with stream is set to the // position represented by pos, which is a pointer to an fpos_t object whose // value shall have been previously obtained by a call to fgetpos. // // The end-of-file internal indicator of the stream is cleared after a // successful call to this function, and all effects from previous calls to // ungetc on this stream are dropped. // // On streams open for update (read+write), a call to fsetpos allows to switch // between reading and writing. // // A similar function, fseek, can be used to set arbitrary positions on streams // open in binary mode. func Fsetpos(stream *File, pos *int32) int32 { return Fseek(stream, int32(*pos), 0) } // Printf handles printf(). // // Writes the C string pointed by format to the standard output (stdout). If // format includes format specifiers (subsequences beginning with %), the // additional arguments following format are formatted and inserted in the // resulting string replacing their respective specifiers. func Printf(format *byte, args ...interface{}) int32 { realArgs := []interface{}{} // Convert any C strings into Go strings. typeOfByteSlice := reflect.TypeOf((*byte)(nil)) for _, arg := range args { if reflect.TypeOf(arg) == typeOfByteSlice { realArgs = append(realArgs, CStringToString(arg.(*byte))) } else { realArgs = append(realArgs, arg) } } n, _ := fmt.Printf(CStringToString(format), realArgs...) return int32(n) } // Puts handles puts(). // // Writes the C string pointed by str to the standard output (stdout) and // appends a newline character ('\n'). // // The function begins copying from the address specified (str) until it reaches // the terminating null character ('\0'). This terminating null-character is not // copied to the stream. // // Notice that puts not only differs from fputs in that it uses stdout as // destination, but it also appends a newline character at the end automatically // (which fputs does not). func Puts(str *byte) int32 { n, _ := fmt.Println(CStringToString(str)) return int32(n) } // Scanf handles scanf(). // // Reads data from stdin and stores them according to the parameter format into // the locations pointed by the additional arguments. // // The additional arguments should point to already allocated objects of the // type specified by their corresponding format specifier within the format // string. func Scanf(format *byte, args ...interface{}) int32 { realArgs := prepareArgsForScanf(args) // We cannot use fmt.Scanf() here because that would use the real stdin // which does not work under test. See docs for noarch.Stdin. n, _ := fmt.Fscanf(Stdin.OsFile, CStringToString(format), realArgs...) finalizeArgsForScanf(realArgs, args) return int32(n) } // Putchar handles putchar(). // // Writes a character to the standard output (stdout). // // It is equivalent to calling putc with stdout as second argument. func Putchar(character int32) { fmt.Printf("%c", character) } // Sprintf handles sprintf(). // // Writes the C string pointed by format to the standard output (stdout). If // format includes format specifiers (subsequences beginning with %), the // additional arguments following format are formatted and inserted in the // resulting string replacing their respective specifiers. func Sprintf(buffer, format *byte, args ...interface{}) int32 { realArgs := []interface{}{} realArgs = append(realArgs, convert(args)...) result := fmt.Sprintf(CStringToString(format), realArgs...) var pBuf *byte for i := range []byte(result) { pBuf = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buffer)) + uintptr(i))) *pBuf = result[i] } pBuf = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buffer)) + uintptr(len(result)))) *pBuf = '\x00' n := len(result) return int32(n) } // Vsprintf handles vsprintf(). // // Writes the C string pointed by format to the standard output (stdout). If // format includes format specifiers (subsequences beginning with %), the // additional arguments following format are formatted and inserted in the // resulting string replacing their respective specifiers. func Vsprintf(buffer, format *byte, args VaList) int32 { realArgs := []interface{}{} realArgs = append(realArgs, convert(args.Args)...) result := fmt.Sprintf(CStringToString(format), realArgs...) var pBuf *byte for i := range []byte(result) { pBuf = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buffer)) + uintptr(i))) *pBuf = result[i] } pBuf = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buffer)) + uintptr(len(result)))) *pBuf = '\x00' n := len(result) return int32(n) } // Snprintf handles snprintf(). // // Writes the C string pointed by format to the standard output (stdout). If // format includes format specifiers (subsequences beginning with %), the // additional arguments following format are formatted and inserted in the // resulting string replacing their respective specifiers. func Snprintf(buffer *byte, n int32, format *byte, args ...interface{}) int32 { return internalVsnprintf(buffer, n, format, args) } // convert - convert va_list func convert(arg interface{}) (result []interface{}) { typeOfByteSlice := reflect.TypeOf((*byte)(nil)) if reflect.TypeOf(arg) == typeOfByteSlice { return []interface{}{CStringToString(arg.(*byte))} } if reflect.TypeOf(arg).Kind() == reflect.Slice { arg := arg.([]interface{}) for j := 0; j < len(arg); j++ { result = append(result, convert(arg[j])...) } return result } return []interface{}{arg} } // Vsnprintf handles vsnprintf(). // // Writes the C string pointed by format to the standard output (stdout). If // format includes format specifiers (subsequences beginning with %), the // additional arguments following format are formatted and inserted in the // resulting string replacing their respective specifiers. func Vsnprintf(buffer *byte, n int32, format *byte, args VaList) int32 { return internalVsnprintf(buffer, n, format, args.Args) } func internalVsnprintf(buffer *byte, n int32, format *byte, args ...interface{}) int32 { realArgs := []interface{}{} realArgs = append(realArgs, convert(args)...) result := fmt.Sprintf(CStringToString(format), realArgs...) if len(result) > int(n) { result = result[:n] } var pBuf *byte for i, b := range []byte(result) { pBuf = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buffer)) + uintptr(i))) *pBuf = b } pBuf = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(buffer)) + uintptr(len(result)))) *pBuf = '\x00' return int32(len(result)) } // Perror handles perror(). // // Interprets the value of errno as an error message, and prints it to stderr // (the standard error output stream, usually the console), optionally preceding // it with the custom message specified in str. // // errno is an integral variable whose value describes the error condition or // diagnostic information produced by a call to a library function (any function of // the C standard library may set a value for errno, even if not explicitly specified // in this reference, and even if no error happened), see errno for more info. // // If the parameter str is not a null pointer, str is printed followed by a colon (:) // and a space. Then, whether str was a null pointer or not, the generated error // description is printed followed by a newline character ('\n'). // // perror should be called right after the error was produced, otherwise it can be // overwritten by calls to other functions. func Perror(str *byte) { var buffer []byte var seek []byte errstr := Strerror(*Errno()) var ( lenStr = Strlen(str) lenErrStr = Strlen(errstr) strSlice = toByteSlice(str, lenStr) errstrSlice = toByteSlice(errstr, lenErrStr) ) if lenStr := Strlen(str); lenStr > 0 { buffer = make([]byte, int(lenStr)+3+int(lenErrStr)) copy(buffer, strSlice) seek = buffer[lenStr:] copy(seek, []byte(": ")) seek = seek[2:] } else { buffer = make([]byte, int(lenErrStr)+1) seek = buffer[:] } copy(seek, errstrSlice) seek[len(seek)-1] = '\n' fmt.Fprint(Stderr.OsFile, string(buffer)) } c2go-0.26.10/noarch/stdlib.go000066400000000000000000000360341410601753200156010ustar00rootroot00000000000000package noarch import ( "math" "os" "strconv" "strings" "github.com/elliotchance/c2go/util" "math/rand" "sync" "unsafe" ) // DivT is the representation of "div_t". It is used by div(). type DivT struct { Quot int32 // quotient Rem int32 // remainder } // LdivT is the representation of "ldiv_t". It is used by ldiv(). type LdivT struct { Quot int32 // quotient Rem int32 // remainder } // LldivT is the representation of "lldiv_t". It is used by lldiv(). type LldivT struct { Quot int64 // quotient Rem int64 // remainder } // Abs returns the absolute value of parameter n. // // In C++, this function is also overloaded in header for floating-point // types (see cmath abs), in header for complex numbers (see complex // abs), and in header for valarrays (see valarray abs). func Abs(n int32) int32 { if n < 0 { return -n } return n } // Atof parses the C string str, interpreting its content as a floating point // number and returns its value as a double. // // The function first discards as many whitespace characters (as in isspace) as // necessary until the first non-whitespace character is found. Then, starting // from this character, takes as many characters as possible that are valid // following a syntax resembling that of floating point literals (see below), // and interprets them as a numerical value. The rest of the string after the // last valid character is ignored and has no effect on the behavior of this // function. // // C90 (C++98): A valid floating point number for atof using the "C" locale is // formed by an optional sign character (+ or -), followed by a sequence of // digits, optionally containing a decimal-point character (.), optionally // followed by an exponent part (an e or E character followed by an optional // sign and a sequence of digits). // // C99/C11 (C++11): A valid floating point number for atof using the "C" locale // is formed by an optional sign character (+ or -), followed by one of: // // - A sequence of digits, optionally containing a decimal-point character // (.), optionally followed by an exponent part (an e or E character // followed by an optional sign and a sequence of digits). // - A 0x or 0X prefix, then a sequence of hexadecimal digits (as in isxdigit) // optionally containing a period which separates the whole and fractional // number parts. Optionally followed by a power of 2 exponent (a p or P // character followed by an optional sign and a sequence of hexadecimal // digits). // - INF or INFINITY (ignoring case). // - NAN or NANsequence (ignoring case), where sequence is a sequence of // characters, where each character is either an alphanumeric character (as // in isalnum) or the underscore character (_). // // If the first sequence of non-whitespace characters in str does not form a // valid floating-point number as just defined, or if no such sequence exists // because either str is empty or contains only whitespace characters, no // conversion is performed and the function returns 0.0. func Atof(str *byte) float64 { f, _ := atof(str) return f } // Atoi parses the C-string str interpreting its content as an integral number, // which is returned as a value of type int. // // The function first discards as many whitespace characters (as in isspace) as // necessary until the first non-whitespace character is found. Then, starting // from this character, takes an optional initial plus or minus sign followed by // as many base-10 digits as possible, and interprets them as a numerical value. // // The string can contain additional characters after those that form the // integral number, which are ignored and have no effect on the behavior of this // function. // // If the first sequence of non-whitespace characters in str is not a valid // integral number, or if no such sequence exists because either str is empty or // it contains only whitespace characters, no conversion is performed and zero // is returned. func Atoi(str *byte) int32 { return int32(Atol(str)) } // Atol parses the C-string str interpreting its content as an integral number, // which is returned as a value of C type "long int". // // The function first discards as many whitespace characters (as in isspace) as // necessary until the first non-whitespace character is found. Then, starting // from this character, takes an optional initial plus or minus sign followed by // as many base-10 digits as possible, and interprets them as a numerical value. // // The string can contain additional characters after those that form the // integral number, which are ignored and have no effect on the behavior of this // function. // // If the first sequence of non-whitespace characters in str is not a valid // integral number, or if no such sequence exists because either str is empty or // it contains only whitespace characters, no conversion is performed and zero // is returned. func Atol(str *byte) int32 { return int32(Atoll(str)) } // Atoll parses the C-string str interpreting its content as an integral number, // which is returned as a value of C type long long int. // // This function operates like atol to interpret the string, but produces // numbers of type long long int (see atol for details on the interpretation // process). func Atoll(str *byte) int64 { x, _ := atoll(str, 10) return x } func atoll(str *byte, radix int32) (int64, int) { // First start by removing any trailing whitespace. We need to record how // much whitespace is trimmed off for the correct offset later. cStr := CStringToString(str) beforeLength := len(cStr) s := strings.TrimSpace(cStr) whitespaceOffset := beforeLength - len(s) // We must convert the input to lowercase so satisfy radix > 10. if radix > 10 { s = strings.ToLower(s) } // We must stop consuming characters when we get to a character that is // invalid for the radix. Build a regex to satisfy this. rx := "" var i int32 for ; i < radix; i++ { if i < 10 { rx += string(48 + i) } else { rx += string(87 + i) } } r := util.GetRegex(`^([+-]?[` + rx + `]+)`) match := r.FindStringSubmatch(s) if match == nil { return 0, 0 } // We do not care about the error here because it should be impossible. v, _ := strconv.ParseInt(match[1], int(radix), 64) return v, whitespaceOffset + len(match[1]) } // Div returns the integral quotient and remainder of the division of numer by // denom ( numer/denom ) as a structure of type div_t, ldiv_t or lldiv_t, which // has two members: quot and rem. func Div(numer, denom int32) DivT { return DivT{ Quot: numer / denom, Rem: numer % denom, } } // Exit uses os.Exit to stop program execution. func Exit(exitCode int32) { os.Exit(int(exitCode)) } // Getenv retrieves a C-string containing the value of the environment variable // whose name is specified as argument. If the requested variable is not part of // the environment list, the function returns a null pointer. // // The pointer returned points to an internal memory block, whose content or // validity may be altered by further calls to getenv (but not by other library // functions). // // The string pointed by the pointer returned by this function shall not be // modified by the program. Some systems and library implementations may allow // to change environmental variables with specific functions (putenv, // setenv...), but such functionality is non-portable. func Getenv(name *byte) *byte { key := CStringToString(name) if env, found := os.LookupEnv(key); found { return StringToCString(env) } return nil } // Labs returns the absolute value of parameter n ( /n/ ). // // This is the long int version of abs. func Labs(n int32) int32 { if n < 0 { return -n } return n } // Ldiv returns the integral quotient and remainder of the division of numer by // denom ( numer/denom ) as a structure of type ldiv_t, which has two members: // quot and rem. func Ldiv(numer, denom int32) LdivT { return LdivT{ Quot: numer / denom, Rem: numer % denom, } } // Llabs returns the absolute value of parameter n ( /n/ ). // // This is the long long int version of abs. func Llabs(n int64) int64 { if n < 0 { return -n } return n } // Lldiv returns the integral quotient and remainder of the division of numer by // denom ( numer/denom ) as a structure of type lldiv_t, which has two members: // quot and rem. func Lldiv(numer, denom int64) LldivT { return LldivT{ Quot: numer / denom, Rem: numer % denom, } } // Rand returns a random number using math/rand.Int(). func Rand() int32 { return int32(rand.Int()) } // Strtod parses the C-string str interpreting its content as a floating point // number (according to the current locale) and returns its value as a double. // If endptr is not a null pointer, the function also sets the value of endptr // to point to the first character after the number. // // The function first discards as many whitespace characters (as in isspace) as // necessary until the first non-whitespace character is found. Then, starting // from this character, takes as many characters as possible that are valid // following a syntax resembling that of floating point literals (see below), // and interprets them as a numerical value. A pointer to the rest of the string // after the last valid character is stored in the object pointed by endptr. func Strtod(str *byte, endptr **byte) float64 { f, fLen := atof(str) // FIXME: This is actually creating new data for the returned pointer, // rather than returning the correct reference. This means that applications // that modify the returned pointer will not be manipulating the original // str. if endptr != nil { *endptr = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(str)) + uintptr(fLen))) } return f } // Strtof works the same way as Strtod but returns a float. func Strtof(str *byte, endptr **byte) float32 { return float32(Strtod(str, endptr)) } // Strtold works the same way as Strtod but returns a long double. func Strtold(str *byte, endptr **byte) float64 { return Strtod(str, endptr) } // Strtol parses the C-string str interpreting its content as an integral number // of the specified base, which is returned as a long int value. If endptr is // not a null pointer, the function also sets the value of endptr to point to // the first character after the number. // // The function first discards as many whitespace characters as necessary until // the first non-whitespace character is found. Then, starting from this // character, takes as many characters as possible that are valid following a // syntax that depends on the base parameter, and interprets them as a numerical // value. Finally, a pointer to the first character following the integer // representation in str is stored in the object pointed by endptr. // // If the value of base is zero, the syntax expected is similar to that of // integer constants, which is formed by a succession of: // // - An optional sign character (+ or -) // - An optional prefix indicating octal or hexadecimal base ("0" or "0x"/"0X" // respectively) // // A sequence of decimal digits (if no base prefix was specified) or either // octal or hexadecimal digits if a specific prefix is present // // If the base value is between 2 and 36, the format expected for the integral // number is a succession of any of the valid digits and/or letters needed to // represent integers of the specified radix (starting from '0' and up to // 'z'/'Z' for radix 36). The sequence may optionally be preceded by a sign // (either + or -) and, if base is 16, an optional "0x" or "0X" prefix. // // If the first sequence of non-whitespace characters in str is not a valid // integral number as defined above, or if no such sequence exists because // either str is empty or it contains only whitespace characters, no conversion // is performed. // // For locales other than the "C" locale, additional subject sequence forms may // be accepted. func Strtol(str *byte, endptr **byte, radix int32) int32 { return int32(Strtoll(str, endptr, radix)) } // Strtoll works the same way as Strtol but returns a long long. func Strtoll(str *byte, endptr **byte, radix int32) int64 { x, xLen := atoll(str, radix) // FIXME: This is actually creating new data for the returned pointer, // rather than returning the correct reference. This means that applications // that modify the returned pointer will not be manipulating the original // str. if endptr != nil { *endptr = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(str)) + uintptr(xLen))) } return x } // Strtoul works the same way as Strtol but returns a long unsigned int. func Strtoul(str *byte, endptr **byte, radix int32) uint32 { return uint32(Strtoll(str, endptr, radix)) } // Strtoull works the same way as Strtol but returns a long long unsigned int. func Strtoull(str *byte, endptr **byte, radix int32) uint64 { return uint64(Strtoll(str, endptr, radix)) } var ( memMgmt map[uint64]interface{} memSync sync.Mutex ) func init() { memMgmt = make(map[uint64]interface{}) } // Malloc returns a pointer to a memory block of the given length. // // To prevent the Go garbage collector from collecting this memory, // we store the whole block in a map. func Malloc(numBytes int32) unsafe.Pointer { memBlock := make([]byte, numBytes) addr := uint64(uintptr(unsafe.Pointer(&memBlock[0]))) memSync.Lock() defer memSync.Unlock() memMgmt[addr] = memBlock return unsafe.Pointer(&memBlock[0]) } // Free removes the reference to this memory address, // so that the Go GC can free it. func Free(anything unsafe.Pointer) { addr := uint64(uintptr(anything)) memSync.Lock() defer memSync.Unlock() delete(memMgmt, addr) } func atof(str *byte) (float64, int32) { // First start by removing any trailing whitespace. We have to record how // much whitespace is trimmed off to correct for the final length. cStr := CStringToString(str) beforeLength := len(cStr) s := strings.TrimSpace(cStr) whitespaceLength := beforeLength - len(s) // Now convert to lowercase, this makes the regexp and comparisons easier // and doesn't change the value. s = strings.ToLower(s) // 1. Hexadecimal integer? This must be checked before floating-point // because it starts with a 0. r := util.GetRegex(`^([+-])?0x([0-9a-f]+)(p[-+]?[0-9a-f]+)?`) match := r.FindStringSubmatch(s) if match != nil { n, err := strconv.ParseUint(match[2], 16, 32) if err == nil { f := float64(n) if match[1] == "-" { f *= -1 } if match[3] != "" { p, err := strconv.Atoi(match[3][1:]) if err != nil { return 0, 0 } f *= math.Pow(2, float64(p)) } return f, int32(whitespaceLength + len(match[0])) } return 0, 0 } // 2. Floating-point number? r = util.GetRegex(`^[+-]?\d*(\.\d*)?(e[+-]?\d+)?`) match = r.FindStringSubmatch(s) if match != nil { f, err := strconv.ParseFloat(match[0], 64) if err == nil { return f, int32(whitespaceLength + len(match[0])) } } // 3. Infinity? if s == "infinity" || s == "+infinity" || s == "inf" || s == "+inf" { return math.Inf(1), int32(len(s)) } if s == "-infinity" || s == "-inf" { return math.Inf(-1), int32(len(s)) } // 4. Not a number? if len(s) > 2 && s[:3] == "nan" { return math.NaN(), 3 } if len(s) > 3 && s[1:4] == "nan" { return math.NaN(), 4 } return 0, 0 } c2go-0.26.10/noarch/string.go000066400000000000000000000136121410601753200156230ustar00rootroot00000000000000package noarch import ( "bytes" "strings" "unsafe" ) // Strlen returns the length of a string. // // The length of a C string is determined by the terminating null-character: A // C string is as long as the number of characters between the beginning of the // string and the terminating null character (without including the terminating // null character itself). func Strlen(a *byte) int32 { // TODO: The transpiler should have a syntax that means this proxy function // does not need to exist. return int32(len(CStringToString(a))) } // Strcpy copies the C string pointed by source into the array pointed by // destination, including the terminating null character (and stopping at that // point). // // To avoid overflows, the size of the array pointed by destination shall be // long enough to contain the same C string as source (including the terminating // null character), and should not overlap in memory with source. func Strcpy(dest, src *byte) *byte { var ( pSrc *byte pDest *byte i int ) for ; ; i++ { pSrc = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(src)) + uintptr(i))) pDest = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(dest)) + uintptr(i))) *pDest = *pSrc // We only need to copy until the first NULL byte. Make sure we also // include that NULL byte on the end. if *pSrc == '\x00' { break } } return dest } // Strncpy copies the first num characters of source to destination. If the end // of the source C string (which is signaled by a null-character) is found // before num characters have been copied, destination is padded with zeros // until a total of num characters have been written to it. // // No null-character is implicitly appended at the end of destination if source // is longer than num. Thus, in this case, destination shall not be considered a // null terminated C string (reading it as such would overflow). // // destination and source shall not overlap (see memmove for a safer alternative // when overlapping). func Strncpy(dest, src *byte, len int32) *byte { // Copy up to the len or first NULL bytes - whichever comes first. var ( pSrc = src pDest = dest i int32 ) for i < len && *pSrc != 0 { *pDest = *pSrc i++ pSrc = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(src)) + uintptr(i))) pDest = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(dest)) + uintptr(i))) } // The rest of the dest will be padded with zeros to the len. for i < len { *pDest = 0 i++ pDest = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(dest)) + uintptr(i))) } return dest } // Strcasestr - function is similar to Strstr(), // but ignores the case of both strings. func Strcasestr(str1, str2 *byte) *byte { a := strings.ToLower(CStringToString(str1)) b := strings.ToLower(CStringToString(str2)) index := strings.Index(a, b) if index == -1 { return nil } return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(str1)) + uintptr(index))) } // Strcat - concatenate strings // Appends a copy of the source string to the destination string. // The terminating null character in destination is overwritten by the first // character of source, and a null-character is included at the end // of the new string formed by the concatenation of both in destination. func Strcat(dest, src *byte) *byte { newDest := (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(dest)) + uintptr(Strlen(dest)))) Strcpy(newDest, src) return dest } // Strcmp - compare two strings // Compares the C string str1 to the C string str2. func Strcmp(str1, str2 *byte) int32 { return int32(bytes.Compare([]byte(CStringToString(str1)), []byte(CStringToString(str2)))) } // Strncmp - compare two strings // Compares the C string str1 to the C string str2 upto the first NULL character // or n-th character whichever comes first. func Strncmp(str1, str2 *byte, n int32) int32 { a := []byte(CStringToString(str1)) a = a[:int(min(int(n), len(a)))] b := []byte(CStringToString(str2)) b = b[:int(min(int(n), len(b)))] return int32(bytes.Compare(a, b)) } // Strstr - locate a substring in a string // function locates the first occurrence of the null-terminated string needle // in the null-terminated string haystack. func Strstr(str1, str2 *byte) *byte { a := CStringToString(str1) b := CStringToString(str2) index := strings.Index(a, b) if index == -1 { return nil } return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(str1)) + uintptr(index))) } func min(a, b int) int { if a < b { return a } return b } // Strchr - Locate first occurrence of character in string // See: http://www.cplusplus.com/reference/cstring/strchr/ func Strchr(str *byte, ch int32) *byte { i := 0 var pStr = str for { if *pStr == '\x00' { break } if int32(*pStr) == ch { return pStr } i++ pStr = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(str)) + uintptr(i))) } return nil } // Memset treats dst as a binary array and sets size bytes to the value val. // Returns dst. func Memset(dst unsafe.Pointer, val int32, size int32) unsafe.Pointer { data := toByteSlice((*byte)(dst), size) var i int32 var vb = byte(val) for i = 0; i < size; i++ { data[i] = vb } return dst } // Memcpy treats dst and src as binary arrays and copies size bytes from src to dst. // Returns dst. // While in C it it is undefined behavior to call memcpy with overlapping regions, // in Go we rely on the built-in copy function, which has no such limitation. // To copy overlapping regions in C memmove should be used, so we map that function // to Memcpy as well. func Memcpy(dst unsafe.Pointer, src unsafe.Pointer, size int32) unsafe.Pointer { bDst := toByteSlice((*byte)(dst), size) bSrc := toByteSlice((*byte)(src), size) copy(bDst, bSrc) return dst } // Memcmp compares two binary arrays upto n bytes. // Different from strncmp, memcmp does not stop at the first NULL byte. func Memcmp(src1, src2 unsafe.Pointer, n int32) int32 { b1 := toByteSlice((*byte)(src1), n) b2 := toByteSlice((*byte)(src2), n) return int32(bytes.Compare(b1, b2)) } c2go-0.26.10/noarch/string_test.go000066400000000000000000000011301410601753200166520ustar00rootroot00000000000000package noarch import ( "reflect" "testing" ) func TestStringCopy(t *testing.T) { tests := []struct { name string dst *byte src *byte length int32 want string }{ {"src longer than length", &make([]byte, 4)[0], &[]byte("asdf")[0], 2, "as"}, {"src shorter length", &make([]byte, 4)[0], &append([]byte("as"), 0)[0], 4, "as"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := CStringToString(Strncpy(tt.dst, tt.src, tt.length)); !reflect.DeepEqual(got, tt.want) { t.Errorf("CStringToString() = %v, want %v", got, tt.want) } }) } } c2go-0.26.10/noarch/syslog.go000066400000000000000000000034461410601753200156410ustar00rootroot00000000000000// +build !windows,!nacl,!plan9 package noarch import ( "fmt" "log/syslog" ) // structure to hold information about an open logger. var logger struct { ident string logopt int32 facility syslog.Priority mask int32 w *syslog.Writer } // void closelog(void); func Closelog() { logger.w.Close() } // void openlog(const char *, int, int); // TODO: handle option parameter func Openlog(ident *byte, logopt int32, facility int32) { logger.ident = CStringToString(ident) logger.logopt = logopt // not sure what to do with this yet if anything logger.facility = syslog.Priority(facility) logger.w, _ = syslog.New(logger.facility, logger.ident) } // int setlogmask(int); // TODO func Setlogmask(mask int32) int32 { ret := logger.mask logger.mask = mask return ret } // void syslog(int, const char *, ...); func Syslog(priority int32, format *byte, args ...interface{}) { realArgs := []interface{}{} realArgs = append(realArgs, convert(args)...) msg := fmt.Sprintf(CStringToString(format), realArgs...) internalSyslog(priority, msg) } // void vsyslog(int, const char *, struct __va_list_tag *); func Vsyslog(priority int32, format *byte, args VaList) { realArgs := []interface{}{} realArgs = append(realArgs, convert(args.Args)...) msg := fmt.Sprintf(CStringToString(format), realArgs...) internalSyslog(priority, msg) } func internalSyslog(priority int32, msg string) { // TODO: handle mask switch syslog.Priority(priority) & 0x7 { // get severity case syslog.LOG_EMERG: logger.w.Emerg(msg) case syslog.LOG_CRIT: logger.w.Crit(msg) case syslog.LOG_ERR: logger.w.Err(msg) case syslog.LOG_WARNING: logger.w.Warning(msg) case syslog.LOG_NOTICE: logger.w.Notice(msg) case syslog.LOG_INFO: logger.w.Info(msg) case syslog.LOG_DEBUG: logger.w.Debug(msg) } } c2go-0.26.10/noarch/syslog_nop.go000066400000000000000000000010721410601753200165060ustar00rootroot00000000000000// +build windows nacl plan9 // A nop syslog logger for platforms with no syslog support package noarch // void closelog(void); func Closelog() { } // void openlog(const char *, int, int); func Openlog(ident *byte, logopt int32, facility int32) { } // int setlogmask(int); func Setlogmask(mask int32) int32 { return 0 } // void syslog(int, const char *, ...); func Syslog(priority int32, format *byte, args ...interface{}) { } // void vsyslog(int, const char *, struct __va_list_tag *); func Vsyslog(priority int32, format *byte, args VaList) { } c2go-0.26.10/noarch/time.go000066400000000000000000000063351410601753200152570ustar00rootroot00000000000000package noarch import ( "fmt" "time" ) // TimeT is the representation of "time_t". // For historical reasons, it is generally implemented as an integral value // representing the number of seconds elapsed // since 00:00 hours, Jan 1, 1970 UTC (i.e., a unix timestamp). // Although libraries may implement this type using alternative time // representations. type TimeT int32 // NullToTimeT converts a NULL to an array of TimeT. func NullToTimeT(i int32) *TimeT { return nil } // Time returns the current time. func Time(tloc *TimeT) TimeT { var t = TimeT(int32(time.Now().Unix())) if tloc != nil { *tloc = t } return t } // IntToTimeT converts an int32 to a TimeT. func IntToTimeT(t int32) TimeT { return TimeT(t) } // Ctime converts TimeT to a string. func Ctime(tloc *TimeT) *byte { if tloc != nil { var t = time.Unix(int64(*tloc), 0) return &append([]byte(t.Format(time.ANSIC)+"\n"), 0)[0] } return nil } // TimeTToFloat64 converts TimeT to a float64. It is used by the tests. func TimeTToFloat64(t TimeT) float64 { return float64(t) } // Tm - base struct in "time.h" // Structure containing a calendar date and time broken down into its // components type Tm struct { Tm_sec int32 Tm_min int32 Tm_hour int32 Tm_mday int32 Tm_mon int32 Tm_year int32 Tm_wday int32 Tm_yday int32 Tm_isdst int32 // tm_gmtoff int32 // tm_zone []byte } // Localtime - Convert time_t to tm as local time // Uses the value pointed by timer to fill a tm structure with the values that // represent the corresponding time, expressed for the local timezone. func LocalTime(timer *TimeT) (tm *Tm) { t := time.Unix(int64(*timer), 0) tm = &Tm{} tm.Tm_sec = int32(t.Second()) tm.Tm_min = int32(t.Minute()) tm.Tm_hour = int32(t.Hour()) tm.Tm_mday = int32(t.Day()) tm.Tm_mon = int32(t.Month() - 1) tm.Tm_year = int32(t.Year() - 1900) tm.Tm_wday = int32(t.Weekday()) tm.Tm_yday = int32(t.YearDay() - 1) return } // Gmtime - Convert time_t to tm as UTC time func Gmtime(timer *TimeT) (tm *Tm) { t := time.Unix(int64(*timer), 0) t = t.UTC() tm = &Tm{} tm.Tm_sec = int32(t.Second()) tm.Tm_min = int32(t.Minute()) tm.Tm_hour = int32(t.Hour()) tm.Tm_mday = int32(t.Day()) tm.Tm_mon = int32(t.Month() - 1) tm.Tm_year = int32(t.Year() - 1900) tm.Tm_wday = int32(t.Weekday()) tm.Tm_yday = int32(t.YearDay() - 1) return } // Mktime - Convert tm structure to time_t // Returns the value of type time_t that represents the local time described // by the tm structure pointed by timeptr (which may be modified). func Mktime(tm *Tm) TimeT { t := time.Date(int(tm.Tm_year+1900), time.Month(tm.Tm_mon)+1, int(tm.Tm_mday), int(tm.Tm_hour), int(tm.Tm_min), int(tm.Tm_sec), 0, time.Now().Location()) tm.Tm_wday = int32(t.Weekday()) return TimeT(int32(t.Unix())) } // constants for asctime var wday_name = [...]string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"} var mon_name = [...]string{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", } // Asctime - Convert tm structure to string func Asctime(tm *Tm) *byte { return &append([]byte(fmt.Sprintf("%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", wday_name[tm.Tm_wday], mon_name[tm.Tm_mon], tm.Tm_mday, tm.Tm_hour, tm.Tm_min, tm.Tm_sec, 1900+tm.Tm_year)), 0)[0] } c2go-0.26.10/noarch/util.go000066400000000000000000000122101410601753200152630ustar00rootroot00000000000000package noarch import ( "reflect" "sync" "unsafe" ) // CStringToString returns a string that contains all the bytes in the // provided C string up until the first NULL character. func CStringToString(s *byte) string { if s == nil { return "" } end := -1 for i := 0; ; i++ { if *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(s)) + uintptr(i))) == 0 { end = i break } } if end == -1 { return "" } return string(toByteSlice(s, int32(end))) } // StringToCString returns the C string (also known as a null terminated string) // to be as used as a string in C. func StringToCString(s string) *byte { cString := make([]byte, len(s)+1) copy(cString, []byte(s)) cString[len(s)] = 0 return &cString[0] } // CStringIsNull will test if a C string is NULL. This is equivalent to: // // s == NULL func CStringIsNull(s *byte) bool { if s == nil { return true } return *s == 0 } // CPointerToGoPointer converts a C-style pointer into a Go-style pointer. // // C pointers are represented as slices that have one element pointing to where // the original C pointer would be referencing. This isn't useful if the pointed // value needs to be passed to another Go function in these libraries. // // See also GoPointerToCPointer. func CPointerToGoPointer(a interface{}) interface{} { t := reflect.TypeOf(a).Elem() return reflect.New(t).Elem().Addr().Interface() } // toByteSlice returns a byte slice to a with the given length. func toByteSlice(a *byte, length int32) []byte { header := reflect.SliceHeader{ uintptr(unsafe.Pointer(a)), int(length), int(length), } return (*(*[]byte)(unsafe.Pointer(&header)))[:] } // GoPointerToCPointer does the opposite of CPointerToGoPointer. // // A Go pointer (simply a pointer) is converted back into the original slice // structure (of the original slice reference) so that the calling functions // will be able to see the new data of that pointer. func GoPointerToCPointer(destination interface{}, value interface{}) { v := reflect.ValueOf(destination).Elem() reflect.ValueOf(value).Index(0).Set(v) } // UnsafeSliceToSlice takes a slice and transforms it into a slice of a different type. // For this we need to adjust the length and capacity in accordance with the sizes // of the underlying types. func UnsafeSliceToSlice(a interface{}, fromSize int32, toSize int32) *reflect.SliceHeader { v := reflect.ValueOf(a) // v might not be addressable, use this trick to get v2 = v, // with v2 being addressable v2 := reflect.New(v.Type()).Elem() v2.Set(v) // get a pointer to the SliceHeader // Calling Pointer() on the slice directly only gets a pointer to the 1st element, not the slice header, // which is why we first call Addr() ptr := unsafe.Pointer(v2.Addr().Pointer()) // adjust header to adjust sizes for the new type header := *(*reflect.SliceHeader)(ptr) header.Len = (header.Len * int(fromSize)) / int(toSize) header.Cap = (header.Cap * int(fromSize)) / int(toSize) return &header } // UnsafeSliceToSliceUnlimited takes a slice and transforms it into a slice of a different type. // The length and capacity will be set to unlimited. func UnsafeSliceToSliceUnlimited(a interface{}) *reflect.SliceHeader { v := reflect.ValueOf(a) // v might not be addressable, use this trick to get v2 = v, // with v2 being addressable v2 := reflect.New(v.Type()).Elem() v2.Set(v) // get a pointer to the SliceHeader // Calling Pointer() on the slice directly only gets a pointer to the 1st element, not the slice header, // which is why we first call Addr() ptr := unsafe.Pointer(v2.Addr().Pointer()) // adjust header to adjust sizes for the new type header := *(*reflect.SliceHeader)(ptr) header.Len = 1000000000 header.Cap = 1000000000 return &header } // Safe contains a thread-safe value type Safe struct { value interface{} lock sync.RWMutex } // NewSafe create a new Safe instance given a value func NewSafe(value interface{}) *Safe { return &Safe{value: value, lock: sync.RWMutex{}} } // Get returns the value func (s *Safe) Get() interface{} { s.lock.RLock() defer s.lock.RUnlock() return s.value } // Set sets a new value func (s *Safe) Set(value interface{}) { s.lock.Lock() defer s.lock.Unlock() s.value = value } var ( interfaceMgmt map[reflect.Value]*InterfaceWrapper interfaceSync sync.Mutex ) func init() { interfaceMgmt = make(map[reflect.Value]*InterfaceWrapper) } // InterfaceWrapper is used for those case where we cannot use unsafe.Pointer // the default catch all data type for c2go. // For the moment this is the case for function pointers. type InterfaceWrapper struct { X interface{} } // CastInterfaceToPointer will take an interface and store it in a map by its reflect.Value // the unsafe.Pointer to its containing InterfaceWrapper is returned. // Since no element is ever removed from the map this should only be used for a limited amount // of elements, like function pointers. func CastInterfaceToPointer(in interface{}) unsafe.Pointer { interfaceSync.Lock() defer interfaceSync.Unlock() val := reflect.ValueOf(in) if iw, ok := interfaceMgmt[val]; ok { return unsafe.Pointer(iw) } else { iw := &InterfaceWrapper{ X: in, } interfaceMgmt[val] = iw return unsafe.Pointer(iw) } } c2go-0.26.10/noarch/util_test.go000066400000000000000000000011001410601753200163160ustar00rootroot00000000000000package noarch import ( "reflect" "testing" ) func TestNullTerminatedBytePointer(t *testing.T) { type args struct { s *byte } tests := []struct { name string args args want string }{ {"nil slice", args{nil}, ""}, {"single null-terminated", args{&[]byte{0}[0]}, ""}, {"multi null-terminated", args{&[]byte{'a', 0, 'b', 0}[0]}, "a"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := CStringToString(tt.args.s); !reflect.DeepEqual(got, tt.want) { t.Errorf("CStringToString() = %v, want %v", got, tt.want) } }) } } c2go-0.26.10/preprocessor/000077500000000000000000000000001410601753200152375ustar00rootroot00000000000000c2go-0.26.10/preprocessor/parse_comments_test.go000066400000000000000000000101761410601753200216510ustar00rootroot00000000000000package preprocessor import ( "fmt" "testing" "github.com/elliotchance/c2go/program" ) func TestParseComments(t *testing.T) { testCases := []struct { ent entity code []string comments []program.Comment }{ { ent: entity{positionInSource: 10, include: "file.c"}, code: []string{ "NULL", "// comment1", }, comments: []program.Comment{ program.Comment{ File: "file.c", Line: 10, Comment: "// comment1", }, }, }, { ent: entity{positionInSource: 10, include: "file.c"}, code: []string{ "NULL", "/* comment1 */", }, comments: []program.Comment{ program.Comment{ File: "file.c", Line: 10, Comment: "/* comment1 */", }, }, }, { ent: entity{positionInSource: 10, include: "file.c"}, code: []string{ "NULL", "// comment1", "/* comment2 */", }, comments: []program.Comment{ program.Comment{ File: "file.c", Line: 10, Comment: "// comment1", }, program.Comment{ File: "file.c", Line: 11, Comment: "/* comment2 */", }, }, }, { ent: entity{positionInSource: 10, include: "file.c"}, code: []string{ "NULL", "/* comment2 */", "// comment1", }, comments: []program.Comment{ program.Comment{ File: "file.c", Line: 10, Comment: "/* comment2 */", }, program.Comment{ File: "file.c", Line: 11, Comment: "// comment1", }, }, }, { ent: entity{positionInSource: 10, include: "file.c"}, code: []string{ "NULL", "/* comment */ // comment1", }, comments: []program.Comment{ program.Comment{ File: "file.c", Line: 10, Comment: "/* comment */", }, program.Comment{ File: "file.c", Line: 10, Comment: "// comment1", }, }, }, { ent: entity{positionInSource: 10, include: "file.c"}, code: []string{ "NULL", "// comment1 /* comment */", }, comments: []program.Comment{ program.Comment{ File: "file.c", Line: 10, Comment: "// comment1 /* comment */", }, }, }, { ent: entity{positionInSource: 10, include: "file.c"}, code: []string{ "NULL", "/* Text1", "Text2", "Text3 */", }, comments: []program.Comment{ program.Comment{ File: "file.c", Line: 10, Comment: "/* Text1\nText2\nText3 */", }, }, }, { ent: entity{positionInSource: 10, include: "file.c"}, code: []string{ "NULL", "/* Text-1 */ // Text 0", "/* Text1", "Text2", "Text3 */ // Text 4", "// Text 5", }, comments: []program.Comment{ program.Comment{ File: "file.c", Line: 10, Comment: "/* Text-1 */", }, program.Comment{ File: "file.c", Line: 10, Comment: "// Text 0", }, program.Comment{ File: "file.c", Line: 11, Comment: "/* Text1\nText2\nText3 */", }, program.Comment{ File: "file.c", Line: 13, Comment: "// Text 4", }, program.Comment{ File: "file.c", Line: 14, Comment: "// Text 5", }, }, }, } for i := range testCases { t.Run(fmt.Sprintf("Test:%d", i), func(t *testing.T) { var result []program.Comment for j := range testCases[i].code { testCases[i].ent.lines = append(testCases[i].ent.lines, &testCases[i].code[j]) } testCases[i].ent.parseComments(&result) if len(result) != len(testCases[i].comments) { t.Fatalf("Size of comments is not same\nresult = '%d'\nexpect = '%d'", len(result), len(testCases[i].comments)) } for j := range result { if result[j].File != testCases[i].comments[j].File { t.Fatalf("File is not same") } if result[j].Comment != testCases[i].comments[j].Comment { t.Fatalf("Comment is not same.\nresult = '%s'\nexpect = '%s'", result[j].Comment, testCases[i].comments[j].Comment) } if result[j].Line != testCases[i].comments[j].Line { t.Fatalf("Lines is not same\nresult = '%d'\nexpect = '%d'", result[j].Line, testCases[i].comments[j].Line) } } }) } } c2go-0.26.10/preprocessor/parse_include_list.go000066400000000000000000000014641410601753200214430ustar00rootroot00000000000000package preprocessor import ( "strings" ) // parseIncludeList - parse list of includes // Example : // exit.o: exit.c /usr/include/stdlib.h /usr/include/features.h \ // /usr/include/stdc-predef.h /usr/include/x86_64-linux-gnu/sys/cdefs.h func parseIncludeList(line string) (lines []string, err error) { line = strings.Replace(line, "\n", " ", -1) line = strings.Replace(line, "\t", " ", -1) line = strings.Replace(line, "\r", " ", -1) // Added for Mac endline symbol line = strings.Replace(line, "\\", " ", -1) line = strings.Replace(line, "\xFF", " ", -1) line = strings.Replace(line, "\u0100", " ", -1) parts := strings.Split(line, " ") for _, p := range parts { p = strings.TrimSpace(p) if p == "" { continue } if p[len(p)-1] == ':' { continue } lines = append(lines, p) } return } c2go-0.26.10/preprocessor/parse_include_list_test.go000066400000000000000000000025101410601753200224730ustar00rootroot00000000000000package preprocessor import ( "fmt" "testing" ) func TestParseIncludeList(t *testing.T) { testCases := []struct { inputLine string list []string }{ { inputLine: ` exit.o: exit.c tests.h `, list: []string{"exit.c", "tests.h"}, }, { inputLine: ` exit.o: exit.c /usr/include/stdlib.h /usr/include/features.h \ /usr/include/stdc-predef.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ /usr/lib/llvm-3.8/bin/../lib/clang/3.8.0/include/stddef.h `, list: []string{"exit.c", "/usr/include/stdlib.h", "/usr/include/features.h", "/usr/include/stdc-predef.h", "/usr/include/x86_64-linux-gnu/sys/cdefs.h", "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h", "/usr/lib/llvm-3.8/bin/../lib/clang/3.8.0/include/stddef.h", }, }, } for i, tc := range testCases { t.Run(fmt.Sprintf("Test:%d", i), func(t *testing.T) { actual, err := parseIncludeList(tc.inputLine) if err != nil { t.Fatal(err) } if len(actual) != len(tc.list) { t.Fatalf("Cannot parse line : %s. Actual result : %#v. Expected: %#v", tc.inputLine, actual, tc.list) } for i := range actual { if actual[i] != tc.list[i] { t.Fatalf("Cannot parse 'include' in line : %s. Actual result : %#v. Expected: %#v", tc.inputLine, actual[i], tc.list[i]) } } }) } } c2go-0.26.10/preprocessor/parse_include_preprocessor_line.go000066400000000000000000000020111410601753200242120ustar00rootroot00000000000000package preprocessor import ( "fmt" "strconv" "strings" ) // typically parse that line: // # 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4 func parseIncludePreprocessorLine(line string) (item *entity, err error) { if line[0] != '#' { err = fmt.Errorf("Cannot parse: first symbol is not # in line %s", line) return } i := strings.Index(line, "\"") if i < 0 { err = fmt.Errorf("First index is not correct on line %s", line) return } l := strings.LastIndex(line, "\"") if i >= l { err = fmt.Errorf("Not allowable positions of symbol \" (%d and %d) in line : %s", i, l, line) return } pos, err := strconv.ParseInt(strings.TrimSpace(line[1:i]), 10, 64) if err != nil { err = fmt.Errorf("Cannot parse position in source : %v", err) return } if l+1 < len(line) { item = &entity{ positionInSource: int(pos), include: line[i+1 : l], other: line[l+1:], } } else { item = &entity{ positionInSource: int(pos), include: line[i+1 : l], } } return } c2go-0.26.10/preprocessor/parse_include_preprocessor_line_test.go000066400000000000000000000057161410601753200252700ustar00rootroot00000000000000package preprocessor import ( "fmt" "testing" ) func TestParseIncludePreproccessorLine(t *testing.T) { testCases := []struct { inputLine string out entity }{ { inputLine: `# 1 "/usr/include/x86_64-linux-gnu/bits/sys_errlist.h" 1 3 4`, out: entity{ include: "/usr/include/x86_64-linux-gnu/bits/sys_errlist.h", positionInSource: 1, }, }, { inputLine: `# 26 "/usr/include/x86_64-linux-gnu/bits/sys_errlist.h" 3 4`, out: entity{ include: "/usr/include/x86_64-linux-gnu/bits/sys_errlist.h", positionInSource: 26, }, }, { inputLine: `# 854 "/usr/include/stdio.h" 2 3 4`, out: entity{ include: "/usr/include/stdio.h", positionInSource: 854, }, }, { inputLine: `# 2 "f.c" 2`, out: entity{ include: "f.c", positionInSource: 2, }, }, { inputLine: `# 2 "f.c"`, out: entity{ include: "f.c", positionInSource: 2, }, }, { inputLine: `# 30 "/usr/lib/llvm-3.8/bin/../lib/clang/3.8.0/include/stdarg.h" 3 4`, out: entity{ include: "/usr/lib/llvm-3.8/bin/../lib/clang/3.8.0/include/stdarg.h", positionInSource: 30, }, }, } for i, tc := range testCases { t.Run(fmt.Sprintf("Test:%d", i), func(t *testing.T) { actual, err := parseIncludePreprocessorLine(tc.inputLine) if err != nil { t.Fatal(err) } if len(actual.include) == 0 { t.Fatal("Cannot parse, because result is empty") } if actual.include != tc.out.include { t.Fatalf("Cannot parse line: \"%s\". Result: \"%s\". Expected: \"%s\"", tc.inputLine, actual.include, tc.out.include) } if actual.positionInSource != tc.out.positionInSource { t.Fatalf("Cannot parse source position in line: \"%s\". Result: \"%d\". Expected: \"%d\"", tc.inputLine, actual.positionInSource, tc.out.positionInSource) } }) } } func TestParseIncludePreproccessorLineFail1(t *testing.T) { inputLine := `# A "/usr/include/stdio.h" 2 3 4` _, err := parseIncludePreprocessorLine(inputLine) if err == nil { t.Fatal("Cannot found error in positionInSource") } } func TestParseIncludePreproccessorLineFail2(t *testing.T) { inputLine := ` # 850 "/usr/include/stdio.h" 2 3 4` _, err := parseIncludePreprocessorLine(inputLine) if err == nil { t.Fatal("Cannot give error if first symbol is not #") } } func TestParseIncludePreproccessorLineFail3(t *testing.T) { inputLine := `# 850` _, err := parseIncludePreprocessorLine(inputLine) if err == nil { t.Fatal("Cannot give error if line hanen't include string") } } func TestParseIncludePreproccessorLineFail4(t *testing.T) { inputLine := `# 850 "/usr/include` _, err := parseIncludePreprocessorLine(inputLine) if err == nil { t.Fatal("Cannot give error if wrong format of include line") } } func TestParseIncludePreproccessorLineFail5(t *testing.T) { inputLine := `# 850` _, err := parseIncludePreprocessorLine(inputLine) if err == nil { t.Fatal("Cannot give error if haven`t include line") } } c2go-0.26.10/preprocessor/preprocessor.go000066400000000000000000000201631410601753200203160ustar00rootroot00000000000000package preprocessor import ( "bufio" "bytes" "fmt" "io/ioutil" "os" "os/exec" "path/filepath" "runtime" "strings" "text/scanner" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/util" ) // One simple part of preprocessor code type entity struct { positionInSource int include string other string // Zero index of `lines` is look like that: // # 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4 // After that 0 or more lines of codes lines []*string } func (e *entity) parseComments(comments *[]program.Comment) { var source bytes.Buffer for i := range e.lines { if i == 0 { continue } source.Write([]byte(*e.lines[i])) source.Write([]byte{'\n'}) } var s scanner.Scanner s.Init(strings.NewReader(source.String())) s.Mode = scanner.ScanComments s.Filename = e.include for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() { if scanner.TokenString(tok) == "Comment" { (*comments) = append(*comments, program.Comment{ File: e.include, Line: s.Position.Line + e.positionInSource - 1, Comment: s.TokenText(), }) } } } // isSame - check is Same entities func (e *entity) isSame(x *entity) bool { if e.include != x.include { return false } if e.positionInSource != x.positionInSource { return false } if e.other != x.other { return false } if len(e.lines) != len(x.lines) { return false } for k := range e.lines { is := e.lines[k] js := x.lines[k] if len(*is) != len(*js) { return false } if *is != *js { return false } } return true } // Analyze - separation preprocessor code to part func Analyze(inputFiles, clangFlags []string, verbose bool) (pp []byte, comments []program.Comment, includes []program.IncludeHeader, err error) { var allItems []entity allItems, err = analyzeFiles(inputFiles, clangFlags, verbose) if err != nil { return } // Generate list of user files userSource := map[string]bool{} var us []string us, err = GetIncludeListWithUserSource(inputFiles, clangFlags) if err != nil { return } var all []string all, err = GetIncludeFullList(inputFiles, clangFlags) if err != nil { return } // Generate C header list includes = generateIncludeList(us, all) for j := range us { userSource[us[j]] = true } // Merge the entities var lines []string for i := range allItems { // If found same part of preprocess code, then // don't include in result buffer for transpiling // for avoid dublicate of code var found bool for j := 0; j < i; j++ { if allItems[i].isSame(&allItems[j]) { found = true break } } if found { continue } // Parse comments only for user sources var isUserSource bool if userSource[allItems[i].include] { isUserSource = true } if allItems[i].include[0] == '.' && allItems[i].include[1] == '/' && userSource[allItems[i].include[2:]] { isUserSource = true } if isUserSource { allItems[i].parseComments(&comments) } // Parameter "other" is not included for avoid like: // ./tests/multi/head.h:4:28: error: invalid line marker flag '2': cannot pop empty include stack // # 2 "./tests/multi/main.c" 2 // ^ header := fmt.Sprintf("# %d \"%s\"", allItems[i].positionInSource, allItems[i].include) lines = append(lines, header) if len(allItems[i].lines) > 0 { for ii, l := range allItems[i].lines { if ii == 0 { continue } lines = append(lines, *l) } } } pp = ([]byte)(strings.Join(lines, "\n")) return } // analyzeFiles - analyze single file and separation preprocessor code to part func analyzeFiles(inputFiles, clangFlags []string, verbose bool) (items []entity, err error) { // See : https://clang.llvm.org/docs/CommandGuide/clang.html // clang -E Run the preprocessor stage. var out bytes.Buffer out, err = getPreprocessSources(inputFiles, clangFlags, verbose) if err != nil { return } // Parsing preprocessor file r := bytes.NewReader(out.Bytes()) scanner := bufio.NewScanner(r) scanner.Split(bufio.ScanLines) // counter - get position of line var counter int // item, items - entity of preprocess file var item *entity reg := util.GetRegex("# (\\d+) \".*\".*") for scanner.Scan() { line := scanner.Text() if reg.MatchString(line) { if item != (*entity)(nil) { items = append(items, *item) } item, err = parseIncludePreprocessorLine(line) if err != nil { err = fmt.Errorf("Cannot parse line : %s with error: %s", line, err) return } if item.positionInSource == 0 { // cannot by less 1 for avoid problem with // indentification of "0" AST base element item.positionInSource = 1 } item.lines = make([]*string, 0) } counter++ item.lines = append(item.lines, &line) } if item != (*entity)(nil) { items = append(items, *item) } return } // See : https://clang.llvm.org/docs/CommandGuide/clang.html // clang -E Run the preprocessor stage. func getPreprocessSources(inputFiles, clangFlags []string, verbose bool) (out bytes.Buffer, err error) { // get temp dir dir, err := ioutil.TempDir("", "c2go-union") if err != nil { return } defer func() { _ = os.RemoveAll(dir) }() // file name union file var unionFileName = dir + "/" + "unionFileName.c" // create a body for union file var unionBody string for i := range inputFiles { var absPath string absPath, err = filepath.Abs(inputFiles[i]) if err != nil { return } unionBody += fmt.Sprintf("#include \"%s\"\n", absPath) } // write a union file err = ioutil.WriteFile(unionFileName, []byte(unionBody), 0644) if err != nil { return } // Add open source defines if runtime.GOOS == "darwin" { clangFlags = append(clangFlags, "-D_XOPEN_SOURCE") } else { clangFlags = append(clangFlags, "-D_GNU_SOURCE") } // preprocessor clang var stderr bytes.Buffer var args []string args = append(args, "-E", "-C") args = append(args, clangFlags...) args = append(args, unionFileName) // All inputFiles var outFile bytes.Buffer if verbose { fmt.Println("executing clang:") fmt.Println("clang", strings.Join(args, " ")) } cmd := exec.Command("clang", args...) cmd.Stdout = &outFile cmd.Stderr = &stderr err = cmd.Run() if err != nil { err = fmt.Errorf("preprocess for file: %v\nfailed: %v\nStdErr = %v", inputFiles, err, stderr.String()) return } _, err = out.Write(outFile.Bytes()) if err != nil { return } return } func generateIncludeList(userList, allList []string) ( includes []program.IncludeHeader) { for i := range allList { var isUser bool for j := range userList { if allList[i] == userList[j] { isUser = true break } } includes = append(includes, program.IncludeHeader{ HeaderName: allList[i], IsUserSource: isUser, }) } return } // GetIncludeListWithUserSource - Get list of include files // Example: // $ clang -MM -c exit.c // exit.o: exit.c tests.h func GetIncludeListWithUserSource(inputFiles, clangFlags []string) (lines []string, err error) { return getIncludeList(inputFiles, clangFlags, "-MM") } // GetIncludeFullList - Get full list of include files // Example: // $ clang -M -c triangle.c // triangle.o: triangle.c /usr/include/stdio.h /usr/include/features.h \ // /usr/include/stdc-predef.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \ // /usr/include/x86_64-linux-gnu/bits/wordsize.h \ // /usr/include/x86_64-linux-gnu/gnu/stubs.h \ // /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \ // / ........ and other func GetIncludeFullList(inputFiles, clangFlags []string) (lines []string, err error) { return getIncludeList(inputFiles, clangFlags, "-M") } func getIncludeList(inputFiles, clangFlags []string, flag string) (lines []string, err error) { var out bytes.Buffer var stderr bytes.Buffer var args []string for i := range inputFiles { inputFiles[i], err = filepath.Abs(inputFiles[i]) if err != nil { return } } args = append(args, flag, "-c") args = append(args, inputFiles...) args = append(args, clangFlags...) cmd := exec.Command("clang", args...) cmd.Stdout = &out cmd.Stderr = &stderr err = cmd.Run() if err != nil { err = fmt.Errorf("preprocess failed: %v\nStdErr = %v", err, stderr.String()) return } return parseIncludeList(out.String()) } c2go-0.26.10/program/000077500000000000000000000000001410601753200141605ustar00rootroot00000000000000c2go-0.26.10/program/function_definition.go000066400000000000000000000353551410601753200205570ustar00rootroot00000000000000package program import ( "strings" "github.com/elliotchance/c2go/util" ) // FunctionDefinition contains the prototype definition for a function. type FunctionDefinition struct { // The name of the function, like "printf". Name string // The C return type, like "int". ReturnType string // The C argument types, like ["bool", "int"]. There is currently no way // to represent a varargs. ArgumentTypes []string // If this is not empty then this function name should be used instead // of the Name. Many low level functions have an exact match with a Go // function. For example, "sin()". Substitution string // Can be overridden with the substitution to rearrange the return variables // and parameters. When either of these are nil the behavior is to keep the // single return value and parameters the same. ReturnParameters []int Parameters []int } // Each of the predefined function have a syntax that allows them to be easy to // read (and maintain). For example: // // double __builtin_fabs(double) -> darwin.Fabs // // Declares the prototype of __builtin_fabs (a low level function implemented // only on Mac) with a specific substitution provided. This means that it should // replace any instance of __builtin_fabs with: // // github.com/elliotchance/c2go/darwin.Fabs // // The substitution is optional. // // The substituted function can also move the parameters and return value // positions. This is called a transformation. For example: // // size_t fread(void*, size_t, size_t, FILE*) -> $0, $1 = noarch.Fread($2, $3, $4) // // Where $0 represents the C return value and $1 and above are for each of the // parameters. // // Transformations can also be used to specify variable that need to be passed // by reference by using the prefix "&" instead of "$": // // size_t fread(void*, size_t, size_t, FILE*) -> $0 = noarch.Fread(&1, $2, $3, $4) // var builtInFunctionDefinitions = map[string][]string{ "assert.h": []string{ // darwin/assert.h "int __builtin_expect(int, int) -> darwin.BuiltinExpect", "bool __assert_rtn(const char*, const char*, int, const char*) -> darwin.AssertRtn", // linux/assert.h "bool __assert_fail(const char*, const char*, unsigned int, const char*) -> linux.AssertFail", }, "ctype.h": []string{ // darwin/ctype.h "uint32 __istype(__darwin_ct_rune_t, uint32) -> darwin.IsType", "__darwin_ct_rune_t __isctype(__darwin_ct_rune_t, uint32) -> darwin.IsCType", "__darwin_ct_rune_t __tolower(__darwin_ct_rune_t) -> darwin.ToLower", "__darwin_ct_rune_t __toupper(__darwin_ct_rune_t) -> darwin.ToUpper", "uint32 __maskrune(__darwin_ct_rune_t, uint32) -> darwin.MaskRune", // linux/ctype.h "const unsigned short int** __ctype_b_loc() -> linux.CtypeLoc", "int tolower(int) -> linux.ToLower", "int toupper(int) -> linux.ToUpper", }, "math.h": []string{ // linux/math.h "int __signbitf(float) -> noarch.Signbitf", "int __signbit(double) -> noarch.Signbitd", "int __signbitl(long double) -> noarch.Signbitl", "int __builtin_signbitf(float) -> noarch.Signbitf", "int __builtin_signbit(double) -> noarch.Signbitd", "int __builtin_signbitl(long double) -> noarch.Signbitl", "int __isnanf(float) -> linux.IsNanf", "int __isnan(double) -> noarch.IsNaN", "int __isnanl(long double) -> noarch.IsNaN", "int __isinff(float) -> linux.IsInff", "int __isinf(double) -> linux.IsInf", "int __isinfl(long double) -> linux.IsInf", // darwin/math.h "double __builtin_fabs(double) -> darwin.Fabs", "float __builtin_fabsf(float) -> darwin.Fabsf", "double __builtin_fabsl(double) -> darwin.Fabsl", "double __builtin_inf() -> darwin.Inf", "float __builtin_inff() -> darwin.Inff", "double __builtin_infl() -> darwin.Infl", "Double2 __sincospi_stret(double) -> darwin.SincospiStret", "Float2 __sincospif_stret(float) -> darwin.SincospifStret", "Double2 __sincos_stret(double) -> darwin.SincosStret", "Float2 __sincosf_stret(float) -> darwin.SincosfStret", "float __builtin_huge_valf() -> darwin.Inff", "int __inline_signbitf(float) -> noarch.Signbitf", "int __inline_signbitd(double) -> noarch.Signbitd", "int __inline_signbitl(long double) -> noarch.Signbitl", "double __builtin_nanf(const char*) -> darwin.NaN", // math.h "double acos(double) -> math.Acos", "double asin(double) -> math.Asin", "double atan(double) -> math.Atan", "double atan2(double, double) -> math.Atan2", "double ceil(double) -> math.Ceil", "double cos(double) -> math.Cos", "double cosh(double) -> math.Cosh", "double exp(double) -> math.Exp", "double fabs(double) -> math.Abs", "double floor(double) -> math.Floor", "double fmod(double, double) -> math.Mod", "double ldexp(double, int) -> noarch.Ldexp", "double log(double) -> math.Log", "double log10(double) -> math.Log10", "double pow(double, double) -> math.Pow", "double sin(double) -> math.Sin", "double sinh(double) -> math.Sinh", "double sqrt(double) -> math.Sqrt", "double tan(double) -> math.Tan", "double tanh(double) -> math.Tanh", }, "stdio.h": []string{ // linux/stdio.h "int _IO_getc(FILE*) -> noarch.Fgetc", "int _IO_putc(int, FILE*) -> noarch.Fputc", // stdio.h "int printf(const char*) -> noarch.Printf", "int scanf(const char*) -> noarch.Scanf", "int putchar(int) -> noarch.Putchar", "int puts(const char *) -> noarch.Puts", "FILE* fopen(const char *, const char *) -> noarch.Fopen", "int fclose(FILE*) -> noarch.Fclose", "int remove(const char*) -> noarch.Remove", "int rename(const char*, const char*) -> noarch.Rename", "int fputs(const char*, FILE*) -> noarch.Fputs", "FILE* tmpfile() -> noarch.Tmpfile", "char* fgets(char*, int, FILE*) -> noarch.Fgets", "void rewind(FILE*) -> noarch.Rewind", "int feof(FILE*) -> noarch.Feof", "int ferror(FILE*) -> noarch.Ferror", "char* tmpnam(char*) -> noarch.Tmpnam", "int fflush(FILE*) -> noarch.Fflush", "int fprintf(FILE*, const char*) -> noarch.Fprintf", "int fscanf(FILE*, const char*) -> noarch.Fscanf", "int fgetc(FILE*) -> noarch.Fgetc", "int fputc(int, FILE*) -> noarch.Fputc", "int getc(FILE*) -> noarch.Fgetc", "int getchar() -> noarch.Getchar", "int putc(int, FILE*) -> noarch.Fputc", "int fseek(FILE*, long int, int) -> noarch.Fseek", "long ftell(FILE*) -> noarch.Ftell", "int fread(void*, int, int, FILE*) -> noarch.Fread", "int fwrite(char*, int, int, FILE*) -> noarch.Fwrite", "int fgetpos(FILE*, int*) -> noarch.Fgetpos", "int fsetpos(FILE*, int*) -> noarch.Fsetpos", "int sprintf(char*, const char *) -> noarch.Sprintf", "int snprintf(char*, int, const char *) -> noarch.Snprintf", "int vsprintf(char*, const char *, struct __va_list_tag *) -> noarch.Vsprintf", "int vsnprintf(char*, int, const char *, struct __va_list_tag *) -> noarch.Vsnprintf", "void perror(char*) -> noarch.Perror", "void clearerr(FILE*) -> noarch.Clearerr", // darwin/stdio.h "int __builtin___sprintf_chk(char*, int, int, char*) -> darwin.BuiltinSprintfChk", "int __builtin___snprintf_chk(char*, int, int, int, char*) -> darwin.BuiltinSnprintfChk", "int __builtin___vsprintf_chk(char*, int, int, char *, struct __va_list_tag *) -> darwin.BuiltinVsprintfChk", "int __builtin___vsnprintf_chk(char*, int, int, int, char*, struct __va_list_tag *) -> darwin.BuiltinVsnprintfChk", }, "string.h": []string{ // string.h "char* strcasestr(const char*, const char*) -> noarch.Strcasestr", "char* strcat(char *, const char *) -> noarch.Strcat", "int strcmp(const char *, const char *) -> noarch.Strcmp", "char* strerror(int) -> noarch.Strerror", // should be: "int strncmp(const char*, const char*, size_t) -> noarch.Strncmp", "int strncmp(const char *, const char *, int) -> noarch.Strncmp", "char * strchr(char *, int) -> noarch.Strchr", "char* strcpy(const char*, char*) -> noarch.Strcpy", // should be: "char* strncpy(const char*, char*, size_t) -> noarch.Strncpy", "char* strncpy(const char*, char*, int) -> noarch.Strncpy", // real return type is "size_t", but it is changed to "int" // in according to noarch.Strlen "int strlen(const char*) -> noarch.Strlen", "char* strstr(const char*, const char*) -> noarch.Strstr", // should be: "void* memset(void *, int, size_t) -> noarch.Memset" "void* memset(void *, int, int) -> noarch.Memset", // should be: "void* memcpy(void *, void *, size_t) -> noarch.Memcpy" "void* memcpy(void *, void *, int) -> noarch.Memcpy", // should be: "void* memmove(void *, void *, size_t) -> noarch.Memcpy" "void* memmove(void *, void *, int) -> noarch.Memcpy", // should be: "int memmove(const void *, const void *, size_t) -> noarch.Memcmp" "int memcmp(void *, void *, int) -> noarch.Memcmp", // darwin/string.h // should be: const char*, char*, size_t "char* __builtin___strcpy_chk(const char*, char*, int) -> darwin.BuiltinStrcpy", // should be: const char*, char*, size_t, size_t "char* __builtin___strncpy_chk(const char*, char*, int, int) -> darwin.BuiltinStrncpy", // should be: size_t __builtin_object_size(const void*, int) "int __builtin_object_size(const char*, int) -> darwin.BuiltinObjectSize", // see https://opensource.apple.com/source/Libc/Libc-763.12/include/secure/_string.h.auto.html "char* __builtin___strcat_chk(char *, const char *, int) -> darwin.BuiltinStrcat", "char* __inline_strcat_chk(char *, const char *) -> noarch.Strcat", "void* __builtin___memset_chk(void *, int, int, int) -> darwin.Memset", "void* __inline_memset_chk(void *, int, int) -> noarch.Memset", "void* __builtin___memcpy_chk(void *, void *, int, int) -> darwin.Memcpy", "void* __inline_memcpy_chk(void *, void *, int) -> noarch.Memcpy", "void* __builtin___memmove_chk(void *, void *, int, int) -> darwin.Memcpy", "void* __inline_memmove_chk(void *, void *, int) -> noarch.Memcpy", }, "stdlib.h": []string{ // stdlib.h "int abs(int) -> noarch.Abs", "double atof(const char *) -> noarch.Atof", "int atoi(const char*) -> noarch.Atoi", "long int atol(const char*) -> noarch.Atol", "long long int atoll(const char*) -> noarch.Atoll", "div_t div(int, int) -> noarch.Div", "void exit(int) -> noarch.Exit", "void free(void*) -> noarch.Free", "char* getenv(const char *) -> noarch.Getenv", "long int labs(long int) -> noarch.Labs", "ldiv_t ldiv(long int, long int) -> noarch.Ldiv", "long long int llabs(long long int) -> noarch.Llabs", "lldiv_t lldiv(long long int, long long int) -> noarch.Lldiv", "int rand() -> noarch.Rand", // The real definition is srand(unsigned int) however the type would be // different. It's easier to change the definition than create a proxy // function in stdlib.go. "void srand(long long) -> math/rand.Seed", "double strtod(const char *, char **) -> noarch.Strtod", "float strtof(const char *, char **) -> noarch.Strtof", "long strtol(const char *, char **, int) -> noarch.Strtol", "long double strtold(const char *, char **) -> noarch.Strtold", "long long strtoll(const char *, char **, int) -> noarch.Strtoll", "long unsigned int strtoul(const char *, char **, int) -> noarch.Strtoul", "long long unsigned int strtoull(const char *, char **, int) -> noarch.Strtoull", "void free(void*) -> noarch.Free", }, "syslog.h": []string{ "void openlog(const char *, int, int) -> noarch.Openlog", "int setlogmask(int) -> noarch.Setlogmask", "void syslog(int, const char *) -> noarch.Syslog", "void vsyslog(int, const char *, struct __va_list_tag *) -> noarch.Vsyslog", "void closelog(void) -> noarch.Closelog", }, "time.h": []string{ // time.h "time_t time(time_t *) -> noarch.Time", "char* ctime(const time_t *) -> noarch.Ctime", "struct tm * localtime(const time_t *) -> noarch.LocalTime", "struct tm * gmtime(const time_t *) -> noarch.Gmtime", "time_t mktime(struct tm *) -> noarch.Mktime", "char * asctime(struct tm *) -> noarch.Asctime", }, "endian.h": []string{ // I'm not sure which header file these comes from? "uint32 __builtin_bswap32(uint32) -> darwin.BSwap32", "uint64 __builtin_bswap64(uint64) -> darwin.BSwap64", }, "errno.h": []string{ // linux "int * __errno_location() -> noarch.Errno", // darwin "int * __error() -> noarch.Errno", }, } // GetFunctionDefinition will return nil if the function does not exist (is not // registered). func (p *Program) GetFunctionDefinition(functionName string) *FunctionDefinition { p.loadFunctionDefinitions() if f, ok := p.functionDefinitions[functionName]; ok { return &f } return nil } // AddFunctionDefinition registers a function definition. If the definition // already exists it will be replaced. func (p *Program) AddFunctionDefinition(f FunctionDefinition) { p.loadFunctionDefinitions() p.functionDefinitions[f.Name] = f } // dollarArgumentsToIntSlice converts a list of dollar arguments, like "$1, &2" // into a slice of integers; [1, -2]. // // This function requires at least one argument in s, but only arguments upto // $9 or &9. func dollarArgumentsToIntSlice(s string) []int { r := []int{} multiplier := 1 for _, c := range s { if c == '$' { multiplier = 1 } if c == '&' { multiplier = -1 } if c >= '0' && c <= '9' { r = append(r, multiplier*(int(c)-'0')) } } return r } func (p *Program) loadFunctionDefinitions() { if p.builtInFunctionDefinitionsHaveBeenLoaded { return } p.functionDefinitions = map[string]FunctionDefinition{} p.builtInFunctionDefinitionsHaveBeenLoaded = true for k, v := range builtInFunctionDefinitions { if !p.IncludeHeaderIsExists(k) { continue } for _, f := range v { match := util.GetRegex(`^(.+) ([^ ]+)\(([, a-z*A-Z_0-9]*)\)( -> .+)?$`). FindStringSubmatch(f) // Unpack argument types. argumentTypes := strings.Split(match[3], ",") for i := range argumentTypes { argumentTypes[i] = strings.TrimSpace(argumentTypes[i]) } if len(argumentTypes) == 1 && argumentTypes[0] == "" { argumentTypes = []string{} } // Defaults for transformations. var returnParameters, parameters []int // Substitution rules. substitution := match[4] if substitution != "" { substitution = strings.TrimLeft(substitution, " ->") // The substitution might also rearrange the parameters (return and // parameter transformation). subMatch := util.GetRegex(`^(.*?) = (.*)\((.*)\)$`). FindStringSubmatch(substitution) if len(subMatch) > 0 { returnParameters = dollarArgumentsToIntSlice(subMatch[1]) parameters = dollarArgumentsToIntSlice(subMatch[3]) substitution = subMatch[2] } } if strings.HasPrefix(substitution, "darwin.") || strings.HasPrefix(substitution, "linux.") || strings.HasPrefix(substitution, "noarch.") { substitution = "github.com/elliotchance/c2go/" + substitution } p.AddFunctionDefinition(FunctionDefinition{ Name: match[2], ReturnType: match[1], ArgumentTypes: argumentTypes, Substitution: substitution, ReturnParameters: returnParameters, Parameters: parameters, }) } } } c2go-0.26.10/program/import.go000066400000000000000000000024451410601753200160260ustar00rootroot00000000000000package program import ( "strconv" "strings" ) // Imports returns all of the Go imports for this program. func (p *Program) Imports() []string { return p.imports } // AddImport will append an absolute import if it is unique to the list of // imports for this program. func (p *Program) AddImport(importPath string) { quotedImportPath := strconv.Quote(importPath) if len(importPath) == 0 { return } for _, i := range p.imports { if i == quotedImportPath { // Already imported, ignore. return } } p.imports = append(p.imports, quotedImportPath) } // AddImports is a convienience method for adding multiple imports. func (p *Program) AddImports(importPaths ...string) { for _, importPath := range importPaths { p.AddImport(importPath) } } // ImportType imports a package for a fully qualified type and returns the local // type name. For example: // // t := p.ImportType("github.com/elliotchance/c2go/darwin.CtRuneT") // // Will import "github.com/elliotchance/c2go/darwin" and return (value of t) // "darwin.CtRuneT". func (p *Program) ImportType(name string) string { if strings.Contains(name, ".") { parts := strings.Split(name, ".") p.AddImport(strings.Join(parts[:len(parts)-1], ".")) parts2 := strings.Split(name, "/") return parts2[len(parts2)-1] } return name } c2go-0.26.10/program/program.go000066400000000000000000000350251410601753200161630ustar00rootroot00000000000000// Package program contains high-level orchestration and state of the input and // output program during transpilation. package program import ( "bytes" "fmt" "go/format" "go/token" goast "go/ast" "strings" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/util" ) // StructRegistry is a map of Struct for struct types and union type type StructRegistry map[string]*Struct // HasType method check if type exists func (sr StructRegistry) HasType(typename string) bool { _, exists := sr[typename] return exists } // Program contains all of the input, output and transpition state of a C // program to a Go program. type Program struct { // All of the Go import paths required for this program. imports []string // These are for the output Go AST. FileSet *token.FileSet File *goast.File // One a type is defined it will be ignored if a future type of the same // name appears. typesAlreadyDefined []string // Contains the current function name during the transpilation. Function *ast.FunctionDecl functionDefinitions map[string]FunctionDefinition builtInFunctionDefinitionsHaveBeenLoaded bool // These are used to setup the runtime before the application begins. An // example would be to setup globals with stdin file pointers on certain // platforms. startupStatements []goast.Stmt // This is used to generate globally unique names for temporary variables // and other generated code. See GetNextIdentifier(). nextUniqueIdentifier int // The definitions for defined structs. // TODO: This field should be protected through proper getters and setters. Structs StructRegistry Unions StructRegistry // If verbose is on progress messages will be printed immediately as code // comments (so that they do not interfere with the program output). Verbose bool // Contains the messages (for example, "// Warning") generated when // transpiling the AST. These messages, which are code comments, are // appended to the very top of the output file. See AddMessage(). messages []string // messagePosition - position of slice messages, added like a comment // in output Go code messagePosition int // A map of all the global variables (variables that exist outside of a // function) and their types. GlobalVariables map[string]string // This option is not available through the command line. It is to allow the // internal integration testing to generate the output in the form of a // Go-test rather than a standalone Go file. OutputAsTest bool // EnumConstantToEnum - a map with key="EnumConstant" and value="enum type" // clang don`t show enum constant with enum type, // so we have to use hack for repair the type EnumConstantToEnum map[string]string // EnumTypedefName - a map with key="Name of typedef enum" and // value="exist ot not" EnumTypedefName map[string]bool // TypedefType - map for type alias, for example: // C : typedef int INT; // Map: key = INT, value = int // Important: key and value are C types TypedefType map[string]string // Comments Comments []Comment // commentLine - a map with: // key - filename // value - last comment inserted in Go code commentLine map[string]int // IncludeHeaders - list of C header IncludeHeaders []IncludeHeader // NodeMap - a map containing all the program's nodes with: // key - the node address // value - the node NodeMap map[ast.Address]ast.Node } // Comment - position of line comment '//...' type Comment struct { File string Line int Comment string } // IncludeHeader - struct for C include header type IncludeHeader struct { HeaderName string IsUserSource bool } // NewProgram creates a new blank program. func NewProgram() (p *Program) { defer func() { // Need for "stdbool.h" p.TypedefType["_Bool"] = "signed char" }() return &Program{ imports: []string{}, typesAlreadyDefined: []string{}, startupStatements: []goast.Stmt{}, Structs: StructRegistry(map[string]*Struct{ // Structs without implementations inside system C headers // Example node for adding: // &ast.TypedefDecl{ ... Type:"struct __locale_struct *" ... } "struct __va_list_tag [1]": { Name: "struct __va_list_tag [1]", IsUnion: false, }, // Pos:ast.Position{File:"/usr/include/xlocale.h", Line:27 "struct __locale_struct *": { Name: "struct __locale_struct *", IsUnion: false, }, // Pos:ast.Position{File:"/usr/include/x86_64-linux-gnu/sys/time.h", Line:61 "struct timezone *__restrict": { Name: "struct timezone *__restrict", IsUnion: false, }, }), Unions: make(StructRegistry), Verbose: false, messages: []string{}, GlobalVariables: map[string]string{}, EnumConstantToEnum: map[string]string{}, EnumTypedefName: map[string]bool{}, TypedefType: map[string]string{}, commentLine: map[string]int{}, IncludeHeaders: []IncludeHeader{}, functionDefinitions: map[string]FunctionDefinition{}, NodeMap: map[ast.Address]ast.Node{}, builtInFunctionDefinitionsHaveBeenLoaded: false, } } // AddMessage adds a message (such as a warning or error) comment to the output // file. Usually the message is generated from one of the Generate functions in // the ast package. // // It is expected that the message already have the comment ("//") prefix. // // The message will not be appended if it is blank. This is because the Generate // functions return a blank string conditionally when there is no error. // // The return value will be true if a message was added, otherwise false. func (p *Program) AddMessage(message string) bool { if message == "" { return false } p.messages = append(p.messages, message) // Compactizarion warnings stack if len(p.messages) > 1 { var ( new = len(p.messages) - 1 last = len(p.messages) - 2 ) // Warning collapsing for minimaze warnings warning := "// Warning" if strings.HasPrefix(p.messages[last], warning) { l := p.messages[last][len(warning):] if strings.HasSuffix(p.messages[new], l) { p.messages[last] = p.messages[new] p.messages = p.messages[0:new] } } } return true } // GetMessageComments - get messages "Warnings", "Error" like a comment // Location of comments only NEAR of error or warning and // don't show directly location func (p *Program) GetMessageComments() (_ *goast.CommentGroup) { var group goast.CommentGroup if p.messagePosition < len(p.messages) { for i := p.messagePosition; i < len(p.messages); i++ { group.List = append(group.List, &goast.Comment{ Text: p.messages[i], }) } p.messagePosition = len(p.messages) } return &group } // GetComments - return comments func (p *Program) GetComments(n ast.Position) (out []*goast.Comment) { beginLine := p.commentLine[n.File] lastLine := n.LineEnd for i := range p.Comments { if p.Comments[i].File == n.File { if beginLine < p.Comments[i].Line && p.Comments[i].Line <= lastLine { out = append(out, &goast.Comment{ Text: p.Comments[i].Comment, }) if p.Comments[i].Comment[0:2] == "/*" { out = append(out, &goast.Comment{ Text: "// ", }) } } } } if len(out) > 0 { out = append(out, &goast.Comment{ Text: "// ", }) } p.commentLine[n.File] = lastLine return } // GetStruct returns a struct object (representing struct type or union type) or // nil if doesn't exist. This method can get struct or union in the same way and // distinguish only by the IsUnion field. `name` argument is the C like // `struct a_struct`, it allow pointer type like `union a_union *`. Pointer // types used in a DeclRefExpr in the case a deferenced structure by using `->` // operator to access to a field like this: a_struct->member . // // This method is used in collaboration with the field // "c2go/program".*Struct.IsUnion to simplify the code like in function // "c2go/transpiler".transpileMemberExpr() where the same *Struct value returned // by this method is used in the 2 cases, in the case where the value has a // struct type and in the case where the value has an union type. func (p *Program) GetStruct(name string) *Struct { if name == "" { return nil } last := len(name) - 1 // That allow to get struct from pointer type if name[last] == '*' { name = name[:last] } name = strings.TrimSpace(name) res, ok := p.Structs[name] if ok { return res } return p.Unions[name] } // IsTypeAlreadyDefined will return true if the typeName has already been // defined. // // A type could be defined: // // 1. Initially. That is, before the transpilation starts (hard-coded). // 2. By calling DefineType throughout the transpilation. func (p *Program) IsTypeAlreadyDefined(typeName string) bool { return util.InStrings(typeName, p.typesAlreadyDefined) } // DefineType will record a type as having already been defined. The purpose for // this is to not generate Go for a type more than once. C allows variables and // other entities (such as function prototypes) to be defined more than once in // some cases. An example of this would be static variables or functions. func (p *Program) DefineType(typeName string) { p.typesAlreadyDefined = append(p.typesAlreadyDefined, typeName) } // GetNextIdentifier generates a new globally unique identifier name. This can // be used for variables and functions in generated code. // // The value of prefix is only useful for readability in the code. If the prefix // is an empty string then the prefix "__temp" will be used. func (p *Program) GetNextIdentifier(prefix string) string { if prefix == "" { prefix = "temp" } identifierName := fmt.Sprintf("%s%d", prefix, p.nextUniqueIdentifier) p.nextUniqueIdentifier++ return identifierName } // String generates the whole output Go file as a string. This will include the // messages at the top of the file and all the rendered Go code. func (p *Program) String() string { var buf bytes.Buffer buf.WriteString(fmt.Sprintf(`/* Package %s - transpiled by c2go version: %s If you have found any issues, please raise an issue at: https://github.com/elliotchance/c2go/ */ `, p.File.Name.Name, Version)) // First write all the messages. The double newline afterwards is important // so that the package statement has a newline above it so that the warnings // are not part of the documentation for the package. buf.WriteString(strings.Join(p.messages, "\n") + "\n\n") if err := format.Node(&buf, p.FileSet, p.File); err != nil { // Printing the entire AST will generate a lot of output. However, it is // the only way to debug this type of error. Hopefully the error // (printed immediately afterwards) will give a clue. // // You may see an error like: // // panic: format.Node internal error (692:23: expected selector or // type assertion, found '[') // // This means that when Go was trying to convert the Go AST to source // code it has come across a value or attribute that is illegal. // // The line number it is referring to (in this case, 692) is not helpful // as it references the internal line number of the Go code which you // will never see. // // The "[" means that there is a bracket in the wrong place. Almost // certainly in an identifer, like: // // noarch.IntTo[]byte("foo") // // The "[]" which is obviously not supposed to be in the function name // is causing the syntax error. However, finding the original code that // produced this can be tricky. // // The first step is to filter down the AST output to probably lines. // In the error message it said that there was a misplaced "[" so that's // what we will search for. Using the original command (that generated // thousands of lines) we will add two grep filters: // // go test ... | grep "\[" | grep -v '{$' // # | | // # | ^ This excludes lines that end with "{" // # | which almost certainly won't be what // # | we are looking for. // # | // # ^ This is the character we are looking for. // // Hopefully in the output you should see some lines, like (some lines // removed for brevity): // // 9083 . . . . . . . . . . Name: "noarch.[]byteTo[]int" // 9190 . . . . . . . . . Name: "noarch.[]intTo[]byte" // // These two lines are clearly the error because a name should not look // like this. // // Looking at the full output of the AST (thousands of lines) and // looking at those line numbers should give you a good idea where the // error is coming from; by looking at the parents of the bad lines. _ = goast.Print(p.FileSet, p.File) panic(err) } // Add comments at the end C file for file, beginLine := range p.commentLine { for i := range p.Comments { if p.Comments[i].File == file { if beginLine < p.Comments[i].Line { buf.WriteString(fmt.Sprintln(p.Comments[i].Comment)) } } } } // simplify Go code. Example : // Before: // func compare(a interface { // }, b interface { // }) (c2goDefaultReturn int) { // After : // func compare(a interface {}, b interface {}) (c2goDefaultReturn int) { reg := util.GetRegex("interface( )?{(\r*)\n(\t*)}") return string(reg.ReplaceAll(buf.Bytes(), []byte("interface {}"))) } // IncludeHeaderIsExists - return true if C #include header is inside list func (p *Program) IncludeHeaderIsExists(includeHeader string) bool { for _, inc := range p.IncludeHeaders { if strings.HasSuffix(inc.HeaderName, includeHeader) { return true } } return false } // SetNodes will add the given nodes and all their children to the program's node map. func (p *Program) SetNodes(nodes []ast.Node) { for _, n := range nodes { if n == nil { continue } var setNode = true addr := n.Address() if addr == 0 { setNode = false } else if _, ok := n.(*ast.Record); ok { setNode = false } if setNode { p.NodeMap[addr] = n } p.SetNodes(n.Children()) } } // DeclareType defines a type without adding the real definition of the type to the list // of declarations. This is useful for types which are defined in a header file, but are // implemented in another *.c file. // This way they can already be used for variable declarations and sizeof. func (p *Program) DeclareType(n *ast.RecordDecl, correctName string) (err error) { name := correctName // TODO: Some platform structs are ignored. // https://github.com/elliotchance/c2go/issues/85 if name == "__locale_struct" || name == "__sigaction" || name == "sigaction" { err = nil return } s := NewStruct(n) if s.IsUnion { p.Unions["union "+name] = s } else { p.Structs["struct "+name] = s } return } c2go-0.26.10/program/startup.go000066400000000000000000000016261410601753200162160ustar00rootroot00000000000000package program import ( goast "go/ast" ) // AppendStartupStatement adds a new statement that must be executed when the // program starts up before any other code. These are required to setup state // for global variables like STDIN that might be referenced by the program. func (p *Program) AppendStartupStatement(stmt goast.Stmt) { p.startupStatements = append(p.startupStatements, stmt) } // AppendStartupExpr is a convienience method for adding a new startup statement // that is in the form of an expression. func (p *Program) AppendStartupExpr(e goast.Expr) { p.AppendStartupStatement(&goast.ExprStmt{ X: e, }) } // StartupStatements returns the statements that will be executed before the // program starts. These are required to setup state for global variables like // STDIN that might be referenced by the program. func (p *Program) StartupStatements() []goast.Stmt { return p.startupStatements } c2go-0.26.10/program/struct.go000066400000000000000000000046771410601753200160510ustar00rootroot00000000000000package program import ( "fmt" "strings" "github.com/elliotchance/c2go/ast" ) // Struct represents the definition for a C struct. type Struct struct { // The name of the struct. Name string // True if the struct kind is an union. // This field is used to avoid to dupplicate code for union case the type is the same. // Plus, this field is used in collaboration with the method "c2go/program".*Program.GetStruct() IsUnion bool // Each of the fields and their C type. The field may be a string or an // instance of Struct for nested structures. Fields map[string]interface{} // Each of the field names in the order they were defined. FieldNames []string } // NewStruct creates a new Struct definition from an ast.RecordDecl. func NewStruct(n *ast.RecordDecl) *Struct { fields := make(map[string]interface{}) fieldNames := make([]string, 0, len(n.Children())) for _, field := range n.Children() { switch f := field.(type) { case *ast.FieldDecl: fields[f.Name] = f.Type fieldNames = append(fieldNames, f.Name) case *ast.IndirectFieldDecl: fields[f.Name] = f.Type fieldNames = append(fieldNames, f.Name) case *ast.RecordDecl: fields[f.Name] = NewStruct(f) fieldNames = append(fieldNames, f.Name) case *ast.MaxFieldAlignmentAttr, *ast.AlignedAttr, *ast.TransparentUnionAttr, *ast.FullComment: // FIXME: Should these really be ignored? default: panic(fmt.Sprintf("cannot decode: %#v", f)) } } return &Struct{ Name: n.Name, IsUnion: n.Kind == "union", Fields: fields, FieldNames: fieldNames, } } // IsUnion - return true if the cType is 'union' or // typedef of union func (p *Program) IsUnion(cType string) bool { if strings.HasPrefix(cType, "union ") { return true } if _, ok := p.Unions[cType]; ok { return true } if _, ok := p.Unions["union "+cType]; ok { return true } if _, ok := p.GetBaseTypeOfTypedef("union " + cType); ok { return true } if t, ok := p.GetBaseTypeOfTypedef(cType); ok { if t == cType { panic(fmt.Errorf("Cannot be same name: %s", t)) } if strings.HasPrefix(t, "struct ") { return false } if t == "" { panic(fmt.Errorf("Type cannot be empty")) } return p.IsUnion(t) } return false } // GetBaseTypeOfTypedef - return typedef type func (p *Program) GetBaseTypeOfTypedef(cTypedef string) ( cBase string, ok bool) { cBase, ok = p.TypedefType[cTypedef] if cBase == "" && ok { panic(fmt.Errorf("Type cannot be empty")) } return } c2go-0.26.10/program/version.go000066400000000000000000000003161410601753200161740ustar00rootroot00000000000000package program // Version can be requested through the command line with: // // c2go -v // // See https://github.com/elliotchance/c2go/wiki/Release-Process const Version = "v0.26.0 Erbium 2020-03-17" c2go-0.26.10/program/warnings.go000066400000000000000000000016721410601753200163450ustar00rootroot00000000000000package program import ( "fmt" "reflect" "github.com/elliotchance/c2go/ast" ) // GenerateErrorMessage - generate error message func (p *Program) GenerateErrorMessage(e error, n ast.Node) string { if e != nil { structName := reflect.TypeOf(n).Elem().Name() return fmt.Sprintf("// Error (%s): %s: %s", structName, n.Position().GetSimpleLocation(), e.Error()) } return "" } // GenerateWarningMessage - generate warning message func (p *Program) GenerateWarningMessage(e error, n ast.Node) string { if e != nil { structName := reflect.TypeOf(n).Elem().Name() return fmt.Sprintf("// Warning (%s): %s: %s", structName, n.Position().GetSimpleLocation(), e.Error()) } return "" } // GenerateWarningOrErrorMessage - generate error if it happen func (p *Program) GenerateWarningOrErrorMessage(e error, n ast.Node, isError bool) string { if isError { return p.GenerateErrorMessage(e, n) } return p.GenerateWarningMessage(e, n) } c2go-0.26.10/tests/000077500000000000000000000000001410601753200136535ustar00rootroot00000000000000c2go-0.26.10/tests/argv.c000066400000000000000000000015571410601753200147660ustar00rootroot00000000000000// This file contains tests for the system arguments (argv). #include #include "tests.h" int main(int argc, const char **argv) { plan(2); // When this file is converted to go it is run through "go test" that needs // some extra arguments before the standard C arguments. We need to adjust // an offset so that the C program and the Go program read the same index // for the first index of the real arguments. int offset = 0; // More than three arguments means it must be run under "go test". If not // the assertion immediately below will fail. if (argc > 3) { offset = 3; } // We cannot compare the zeroth argument because it will be different for C // and Go. // is_streq(argv[0], "build/go.out"); is_streq(argv[1 + offset], "some"); is_streq(argv[2 + offset], "args"); done_testing(); } c2go-0.26.10/tests/array.c000066400000000000000000000350541410601753200151440ustar00rootroot00000000000000// Array examples #include "tests.h" #include #define START_TEST(t) \ diag(#t); \ test_##t(); void test_intarr() { int a[3]; a[0] = 5; a[1] = 9; a[2] = -13; is_eq(a[0], 5); is_eq(a[1], 9); is_eq(a[2], -13); } void test_doublearr() { double a[2]; a[0] = 1.2; a[1] = 7; // different type is_eq(a[0], 1.2); is_eq(a[1], 7.0); } void test_intarr_init() { int a[] = {10, 20, 30}; is_eq(a[0], 10); is_eq(a[1], 20); is_eq(a[2], 30); } void test_floatarr_init() { float a[] = {2.2, 3.3, 4.4}; is_eq(a[0], 2.2); is_eq(a[1], 3.3); is_eq(a[2], 4.4); } void test_chararr_init() { char a[] = {97, 98, 99}; is_eq(a[0], 'a'); is_eq(a[1], 'b'); is_eq(a[2], 'c'); } void test_chararr_init2() { char a[] = {'a', 'b', 'c'}; is_eq(a[0], 'a'); is_eq(a[1], 'b'); is_eq(a[2], 'c'); } void test_exprarr() { int a[] = {2 ^ 1, 3 & 1, 4 | 1, (5 + 1)/2}; is_eq(a[0], 3); is_eq(a[1], 1); is_eq(a[2], 5); is_eq(a[3], 3); } struct s { int i; char c; }; void test_structarr() { struct s a[] = {{1, 'a'}, {2, 'b'}}; is_eq(a[0].i, 1); is_eq(a[0].c, 'a'); is_eq(a[1].i, 2); is_eq(a[1].c, 'b'); struct s b[] = {(struct s){1, 'a'}, (struct s){2, 'b'}}; is_eq(b[0].i, 1); is_eq(b[0].c, 'a'); is_eq(b[1].i, 2); is_eq(b[1].c, 'b'); } long dummy(char foo[42]) { return sizeof(foo); } void test_argarr() { char abc[1]; is_eq(8, dummy(abc)); } void test_multidim() { int a[2][3] = {{5,6,7},{50,60,70}}; is_eq(a[1][2], 70); // omit array length int b[][3][2] = {{{1,2},{3,4},{5,6}}, {{6,5},{4,3},{2,1}}}; is_eq(b[1][1][0], 4); // 2 * 3 * 2 * sizeof(int32) is_eq(sizeof(b), 48); struct s c[2][3] = {{{1,'a'},{2,'b'},{3,'c'}}, {{4,'d'},{5,'e'},{6,'f'}}}; is_eq(c[1][1].i, 5); is_eq(c[1][1].c, 'e'); c[1][1] = c[0][0]; is_eq(c[1][1].i, 1); is_eq(c[1][1].c, 'a'); } void test_ptrarr() { int b = 22; int *d[3]; d[1] = &b; is_eq(*(d[1]), 22); int **e[4]; e[0] = d; is_eq(*(e[0][1]), 22); } void test_stringarr_init() { char *a[] = {"a", "bc", "def"}; is_streq(a[0], "a"); is_streq(a[1], "bc"); is_streq(a[2], "def"); } void test_partialarr_init() { // Last 2 values are filled with zeros double a[4] = {1.1, 2.2}; is_eq(a[2], 0.0); is_eq(a[3], 0.0); struct s b[3] = {{97, 'a'}}; is_eq(b[0].i, 97); is_eq(b[2].i, 0); is_eq(b[2].c, 0); } extern int arrayEx[]; int arrayEx[4] = { 1, 2, 3, 4 }; int ff(){ return 3;} double rep_double(double a) { return a; } int rep_int(int a) { return a; } void zero(int *a, int *b, int *c) { *a = *b = *c = 0; } float * next_pointer(float *v) { long l = 1; long p = 2; (void)(l); (void)(p); return p - p + v + l; } double *dvector(long nl, long nh) { double *v; v=(double *)malloc((size_t) ((nh-nl+1+1)*sizeof(double))); for (int i=0;i 1 structs a[] = {{1, 'a'}, {2, 'b'}, {3, 'c'}}; is_eq(a[0].i, 1); is_eq(a[0].c, 'a'); is_eq(a[1].i, 2); is_eq(a[1].c, 'b'); is_eq(a[2].i, 3); is_eq(a[2].c, 'c'); structs *ps = &a; structs *ps2; is_eq(ps->i, 1); ps2 = ps + size; is_eq(ps2->i, 2); ps2 += size; is_eq(ps2->i, 3); is_eq(ps2-ps, 2); ps2 -= size; is_eq(ps2->i, 2); } void test_pointer_minus_pointer() { char *left_ptr; char *right_ptr; char arr[30]; left_ptr = &arr[0]; right_ptr = &arr[20]; is_eq(right_ptr - left_ptr, 20); // tests for pointer to struct with size > 1 structs arr2[30]; structs *left_ptr2 = &arr2[0]; structs *right_ptr2 = &arr2[20]; is_eq(right_ptr2 - left_ptr2, 20); } typedef unsigned char pcre_uchar; typedef unsigned char pcre_uint8; typedef unsigned short pcre_uint16; typedef unsigned int pcre_uint32; #define PT_ANY 0 /* Any property - matches all chars */ #define PT_SC 4 /* Script (e.g. Han) */ #define CHAR_B 'b' #define STR_A "\101" #define STR_a "\141" #define STR_b "\142" #define STR_c "\143" #define STR_e "\145" #define STR_i "\151" #define STR_m "\155" #define STR_n "\156" #define STR_r "\162" #define STR_y "\171" #define STRING_Any0 STR_A STR_n STR_y "\0" #define STRING_Arabic0 STR_A STR_r STR_a STR_b STR_i STR_c "\0" #define STRING_Armenian0 STR_A STR_r STR_m STR_e STR_n STR_i STR_a STR_n "\0" const char _test_utt_names[] = STRING_Any0 STRING_Arabic0 STRING_Armenian0; enum { ucp_Arabic, ucp_Armenian, }; typedef struct { pcre_uint16 name_offset; pcre_uint16 type; pcre_uint16 value; } ucp_type_table; const ucp_type_table _test_utt[] = { { 0, PT_ANY, 0 }, { 4, PT_SC, ucp_Arabic }, { 11, PT_SC, ucp_Armenian } }; int comp (char* name, int i) { return strcmp(name, _test_utt_names + _test_utt[i].name_offset); } void test_arr_to_pointer() { is_true(comp("Any", 0) == 0); is_true(comp("Any", 1) != 0); is_true(comp("Arabic", 1) == 0); is_true(comp("Arabic", 2) != 0); is_true(comp("Armenian", 2) == 0); is_true(comp("Armenian", 1) != 0); pcre_uint32 copynames[1024]; pcre_uint32 *copynames32 = (pcre_uint32 *)copynames; *copynames32 = 42; is_eq(copynames[0], 42); *copynames = 0; is_eq(copynames[0], 0); pcre_uint32 c = 0; pcre_uchar buffer[8]; buffer[0] = 7; is_eq(c, 0); c = *buffer; is_eq(c, 7); } int main() { plan(162); START_TEST(intarr); START_TEST(doublearr); START_TEST(intarr_init); START_TEST(floatarr_init); START_TEST(chararr_init); START_TEST(chararr_init2); START_TEST(exprarr); START_TEST(structarr); START_TEST(argarr); START_TEST(multidim); START_TEST(ptrarr); START_TEST(stringarr_init); START_TEST(partialarr_init); is_eq(arrayEx[1],2.0); diag("Array arithmetic") float a[5]; a[0] = 42.; is_eq(a[0],42.); a[0+1] = 42.; is_eq(a[1],42); a[2] = 42.; is_eq(a[2],42); diag("Pointer arithmetic. Part 1"); float *b; b = (float *)calloc(5,sizeof(float)); *b = 42.; is_eq(*(b+0),42.); *(b+1) = 42.; is_eq(*(b+1),42.); *(2+b) = 42.; is_eq(*(b+2),42.); *(b+ff()) = 45.; is_eq(*(b + 3), 45.); *(ff()+b+1) = 46.; is_eq(*(b + 4), 46.); *(b+ (0 ? 1 : 2)) = -1.; is_eq(*(b+2),-1); *(b + 0) = 1 ; *(b + (int)(*(b + 0)) - 1) = 35; is_eq(*(b+0),35); *(b + (int)((float)(2))) = -45; is_eq(*(b+2),-45); *(b + 1 + 3 + 1 - 5*1 + ff() - 3) = -4.0; is_eq(*(b+0), -4.0); is_eq(*b , -4.0); is_eq((*(b + 1 + 3 + 1 - 5*1 + ff() - 3 + 1) = -48.0,*(b+1)), -48.0); {int rrr;(void)(rrr);} diag("Pointer arithmetic. Part 2") { float *arr; arr = (float*)calloc(1+1,sizeof(float)); is_true(arr != NULL); (void)(arr); } { float *arr; arr = (float *) calloc(1+ff(),sizeof(float)); is_true(arr != NULL); (void)(arr); } { float *arr; arr = (float *) calloc(ff()+ff(),sizeof(float)); is_true(arr != NULL); (void)(arr); } { float *arr; arr = (float *) calloc(ff()+1+0+0+1*0,sizeof(float)); is_true(arr != NULL); (void)(arr); } diag("Pointer to Pointer. 1") { double Var = 42; double **PPptr1; double * PPptr2; PPptr2 = &Var; PPptr1 = &PPptr2; is_eq(**PPptr1,Var) Var = 43; is_eq(**PPptr1,Var) (void)(PPptr1); (void)(PPptr2); } diag("Pointer to Pointer. 2") { double Var = 42.0, **PPptr1, * PPptr2; PPptr2 = &Var; PPptr1 = &PPptr2; is_eq(**PPptr1,Var) Var = 43.0; is_eq(**PPptr1,Var) (void)(PPptr1); (void)(PPptr2); } diag("Pointer to Pointer. 3"); { int i = 50; int ** ptr1; int * ptr2; ptr2 = &i; ptr1 = &ptr2; is_eq(**ptr1, i); is_eq(* ptr2, i); } diag("Pointer to Pointer. 4"); { double arr[5] = {10.,20.,30.,40.,50.}; double *ptr ; ptr = &arr; is_eq(*ptr, 10.); ++ptr; is_eq(*ptr, 20.); } diag("Pointer to Pointer. 5"); { double arr[5] = {10.,20.,30.,40.,50.}; double *ptr ; ptr = &arr; is_eq(*ptr, 10.); ptr += 1; is_eq(*ptr, 20.); } diag("Pointer to Pointer. 6"); { int arr[5] = {10,20,30,40,50}; int *ptr ; ptr = &arr; is_eq(*ptr, 10); ptr = 1 + ptr; is_eq(*ptr, 20); } diag("Pointer to Pointer. 7"); { double arr[5] = {10.,20.,30.,40.,50.}; double *ptr ; ptr = &arr; is_eq(*ptr, 10.); ptr = 1 + ptr; is_eq(*ptr, 20.); } diag("Pointer to Pointer. 8"); { double arr[5] = {10.,20.,30.,40.,50.}; double *ptr ; ptr = &arr; is_eq(*ptr, 10.); ptr++; is_eq(*ptr, 20.); } diag("Pointer to Pointer. 9"); { double arr[5] = {10.,20.,30.,40.,50.}; double *ptr ; ptr = &arr[2]; is_eq(*ptr, 30.); ptr = ptr -1; is_eq(*ptr, 20.); } diag("Pointer to Pointer. 10"); { double arr[5] = {10.,20.,30.,40.,50.}; double *ptr ; ptr = &arr[2]; is_eq(*ptr, 30.); ptr -= 1; is_eq(*ptr, 20.); } diag("Pointer to Pointer. 11"); { double arr[5] = {10.,20.,30.,40.,50.}; double *ptr ; ptr = &arr[2]; is_eq(*ptr, 30.); ptr--; is_eq(*ptr, 20.); } diag("Pointer to Pointer. 12"); { double arr[5] = {10.,20.,30.,40.,50.}; double *ptr ; int i = 0; for (ptr = &arr[0]; i < 5; ptr++){ is_eq(*ptr,arr[i]); i++; } } diag("Operation += 1 for double array"); { float **m; m = (float **) malloc(5*sizeof(float*)); is_not_null(m); m[0] = (float *) malloc(10*sizeof(float)); m[1] = (float *) malloc(10*sizeof(float)); m[0] += 1; (void)(m); pass("ok"); } diag("*Pointer = 0"); { int a,b,c; a = b = c = 10; is_eq(a , 10); zero(&a,&b,&c); is_eq(a , 0); is_eq(b , 0); is_eq(c , 0); pass("ok"); } diag("pointer + long"); { float *v = (float *)malloc(5*sizeof(float)); *(v+0) = 5; *(v+1) = 6; is_eq(*(next_pointer(v)),6); } diag("create array"); { double * arr = dvector(1,12); is_not_null(arr); is_eq(arr[1],42.0); is_eq(arr[9],42.0); (void)(arr); } diag("Increment inside array 1"); { float f[4] = {1.2,2.3,3.4,4.5}; int iter = 0; is_eq(f[iter++] , 1.2); is_eq(f[iter+=1], 3.4); is_eq(f[--iter] , 2.3); } diag("Increment inside array 2"); { struct struct_I_A{ double * arr; int * pos; } ; struct struct_I_A siia[2]; { double t_arr [5]; siia[0].arr = t_arr; } { double t_arr [5]; siia[1].arr = t_arr; } { int t_pos[1]; siia[0].pos = t_pos; } { int t_pos[1]; siia[1].pos = t_pos; } int t = 0; int ii,jj; int one = 1; siia[0].arr[0] = 45.; siia[0].arr[1] = 35.; siia[0].arr[2] = 25.; siia[0].pos[0] = 0; ii = -1; jj = -1; is_eq(siia[0].arr[(t ++, siia[jj += one].pos[ii += one] += one, siia[jj].pos[ii])] , 35.); siia[0].pos[0] = 0; ii = -1; jj = -1; is_eq(siia[0].arr[(t ++, siia[++ jj ].pos[++ ii ] ++, siia[jj].pos[ii] )] , 35.); siia[0].pos[0] = 2; ii = -1; jj = -1; is_eq(siia[0].arr[(t ++, siia[0].pos[ii += 1] -= 1, siia[0].pos[ii])] , 35.); siia[0].pos[0] = 2; ii = -1; jj = -1; is_eq(siia[0].arr[(t ++, siia[0].pos[ii += 1] -- , siia[0].pos[ii] )] , 35.); is_eq(t,4); (void)(t); } diag("Increment inside array 3"); { struct struct_I_A3{ double*arr; int pos; } ; struct struct_I_A3 siia[2]; { double t_arr [5]; siia[0].arr = t_arr; } { double t_arr [5]; siia[1].arr = t_arr; } siia[0].arr[0] = 45.; siia[0].arr[1] = 35.; siia[0].arr[2] = 25.; siia[0].pos = 0; is_eq(siia[0].arr[siia[0].pos += 1] , 35.); siia[0].pos = 0; is_eq(siia[0].arr[siia[0].pos ++ ] , 45.); siia[0].pos = 0; is_eq(siia[0].arr[++ siia[0].pos ] , 35.); siia[0].pos = 2; is_eq(siia[0].arr[siia[0].pos -= 1] , 35.); siia[0].pos = 2; is_eq(siia[0].arr[siia[0].pos -- ] , 25.); } diag("Increment inside array 4"); { struct struct_I_A4{ double*arr ; int pos ; } ; struct struct_I_A4 siia[2]; { double t_arr [5]; siia[0].arr = t_arr; } { double t_arr [5]; siia[1].arr = t_arr; } int t = 0; siia[0].arr[0] = 45.; siia[0].arr[1] = 35.; siia[0].arr[2] = 25.; siia[0].pos = 0; is_eq(siia[0].arr[(t ++ , siia[0].pos += 1)] , 35.); siia[0].pos = 0; is_eq(siia[0].arr[(t ++ ,siia[0].pos ++ )] , 45.); siia[0].pos = 2; is_eq(siia[0].arr[(t ++ ,siia[0].pos -= 1)] , 35.); siia[0].pos = 2; is_eq(siia[0].arr[(t ++, siia[0].pos -- )] , 25.); is_eq(t,4); (void)(t); } diag("Increment inside array 5"); { struct struct_I_A5{ double * arr ; int pos ; } ; struct struct_I_A5 siia[2]; { double t_arr [5]; siia[0].arr = t_arr; } { double t_arr [5]; siia[1].arr = t_arr; } int t = 0; siia[0].arr[0] = 45.; siia[0].arr[1] = 35.; siia[0].arr[2] = 25.; siia[0].pos = 0; is_eq(siia[0].arr[(t ++ , siia[0].pos += 1, siia[0].pos )] , 35.); siia[0].pos = 0; is_eq(siia[0].arr[(t ++ ,siia[0].pos ++ , siia[0].pos )] , 35.); siia[0].pos = 2; is_eq(siia[0].arr[(t ++ ,siia[0].pos -= 1, siia[0].pos )] , 35.); siia[0].pos = 2; is_eq(siia[0].arr[(t ++, siia[0].pos -- , siia[0].pos )] , 35.); is_eq(t,4); (void)(t); } diag("Increment inside array 6"); { struct struct_I_A6{ double * arr ; int * pos ; } ; struct struct_I_A6 siia[2]; { double t_arr [5]; siia[0].arr = t_arr; } { double t_arr [5]; siia[1].arr = t_arr; } { int t_pos[1]; siia[0].pos = t_pos; } { int t_pos[1]; siia[1].pos = t_pos; } int t = 0; siia[0].arr[0] = 45.; siia[0].arr[1] = 35.; siia[0].arr[2] = 25.; siia[0].pos[0] = 0; is_eq(siia[0].arr[(t ++, siia[0].pos[0] += 1)] , 35.); siia[0].pos[0] = 0; is_eq(siia[0].arr[(t ++, siia[0].pos[0] ++ )] , 45.); siia[0].pos[0] = 2; is_eq(siia[0].arr[(t ++, siia[0].pos[0] -= 1)] , 35.); siia[0].pos[0] = 2; is_eq(siia[0].arr[(t ++, siia[0].pos[0] -- )] , 25.); is_eq(t,4); (void)(t); } test_pointer_arith_size_t(); test_pointer_minus_pointer(); diag("negative array index"); { pcre_uchar arr[] = "abcdef"; pcre_uchar *a = &arr[2]; is_eq(*a, 'c'); is_eq(a[-1], 'b'); is_eq(a[-2+1], 'b'); is_eq(*(a-1), CHAR_B); } diag("array to pointer"); test_arr_to_pointer(); done_testing(); } c2go-0.26.10/tests/asm.c000066400000000000000000000017101410601753200145760ustar00rootroot00000000000000// The functions in this file were adapted from: // http://read.cs.ucla.edu/sqlite-anvil/trunk/sqlite-3.6.0/src/hwtime.h // // For more information see the original issue: // https://github.com/elliotchance/c2go/issues/228 #include "tests.h" __inline__ unsigned long sqlite3Hwtime1(void){ unsigned int lo, hi; __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); return (unsigned long)hi << 32 | lo; } // This has been disabled because clang cannot understand the asm{} syntax. //__inline sqlite_uint64 __cdecl sqlite3Hwtime2(void){ // __asm { // rdtsc // ret ; return value at EDX:EAX // } //} __inline__ unsigned long sqlite3Hwtime3(void){ unsigned long val; __asm__ __volatile__ ("rdtsc" : "=A" (val)); return val; } int main() { // There are no actual tests in this file because Go does not support inline // assembly. We will have to revisit this in the future. plan(0); done_testing(); } c2go-0.26.10/tests/assert.c000066400000000000000000000007361410601753200153260ustar00rootroot00000000000000// This file contains tests for assert.h. // // Note: assert() failures print directly. The output of this program will not // be valid TAP. #include #include #include "tests.h" void print_number(int *myInt) { assert(myInt != NULL); printf("%d\n", *myInt); } int main() { plan(0); int a = 10; int *b = NULL; int *c = NULL; b = &a; print_number(b); print_number(c); fail("%s", "It shouldn't make it to here!"); done_testing(); } c2go-0.26.10/tests/cast.c000066400000000000000000000123121410601753200147500ustar00rootroot00000000000000#include #include "tests.h" #define START_TEST(t) \ diag(#t); \ test_##t(); void test_cast() { int c[] = {(int)'a', (int)'b'}; is_eq(c[0], 97); double d = (double) 1; is_eq(d, 1.0); } void test_castbool() { char i1 = (1 == 1); short i2 = (1 == 1); int i3 = (1 == 1); long i4 = (1 == 0); long long i5 = (1 == 0); is_eq((i1==1) && (i2==1) && (i3==1) && (i4==0) && (i5==0), 1); } void char_overflow() { { char c; c = -1; unsigned char u = c; is_eq(u, 256-1); } { char c = -1; unsigned char u = c; is_eq(u, 256-1); } { char c = (-1); unsigned char u = c; is_eq(u, 256-1); } { char c = (((-1))); unsigned char u = c; is_eq(u, 256-1); } } typedef double * vertex; void test_vertex() { diag("vertex"); double a[1]; a[0] = 42; double b[1]; b[0] = 45; double dxoa; vertex triorg = (vertex)(a); vertex triapex = (vertex)(b); dxoa = triorg[0] - triapex[0]; is_eq(dxoa, -3); } static int strlenChar(const char *z){ int n = 0; while( *z ){ if( (0xc0&*(z++))!=0x80 ) n++; } return n; } void test_strCh() { char * z = "Hello, c2go\0"; is_eq(strlenChar(z),11); } typedef unsigned int pcre_uint32; #define CHAR_NBSP ((unsigned char)'\xa0') void test_preprocessor() { int tmp = 160; pcre_uint32 chr = tmp; is_eq(chr, CHAR_NBSP); } typedef unsigned char pcre_uchar; typedef unsigned char pcre_uint8; typedef struct pcre_study_data { pcre_uint8 start_bits[32]; } pcre_study_data; void caststr() { pcre_uchar str[] = "abcd"; is_streq((char *) str, "abcd"); } static const pcre_uchar TEST[] = { 'x', (pcre_uchar) CHAR_NBSP, '\n', '\0' }; #define CHAR_E ((unsigned char) 'e') static const pcre_uchar TEST2[] = { 'x', (pcre_uchar) CHAR_NBSP, '\n', (pcre_uchar) CHAR_E, '\0' }; void test_static_array() { is_eq('x', TEST[0]); is_eq((pcre_uchar) '\xa0', TEST[1]); is_eq('\n', TEST[2]); is_eq('x', TEST2[0]); is_eq('e', TEST2[3]); // can distinguish character at same column in different lines } void castbitwise() { pcre_uint32 x = 0xff; x &= ~0x3c; is_eq(x, 0xc3); } void cast_pointer_diff(pcre_uchar *str, int *x) { pcre_uchar *p = str; pcre_uchar ab = '\0'; *x = (int)(p - str) - ab; } typedef unsigned char x_uint; typedef unsigned char y_uint; typedef struct { unsigned char a; unsigned char b; } z_struct; void test_voidcast() { x_uint x = 42; void * y = &x; y_uint *z = (y_uint*) y; is_eq(42, *z); x_uint arr1[] = { 1, 2, 3, 4 }; y = arr1; z_struct *arr2 = (z_struct*) y; is_eq(1, arr2[0].a); is_eq(2, arr2[0].b); is_eq(3, arr2[1].a); is_eq(4, arr2[1].b); pcre_uchar **stringlist; y = &x; void * py = &y; stringlist = (pcre_uchar **)(py); is_eq(**((x_uint **)py), 42); is_eq(**stringlist, 42); *((const char **)py) = NULL; is_eq(x, 42); is_true(y == NULL); y = &x; *((const pcre_uint8 **)py) = NULL; is_eq(x, 42); is_true(y == NULL); y = &x; *((const pcre_uchar **)py) = NULL; is_eq(x, 42); is_true(y == NULL); } int main() { plan(52); START_TEST(cast); START_TEST(castbool); START_TEST(vertex); START_TEST(strCh); START_TEST(voidcast); { typedef unsigned int u32; u32 x = 42; is_eq(x , 42); u32 a[10]; a[0] = x; is_eq(a[0],42); } { typedef double u32d; u32d x = 42.0; is_eq(x , 42.0); u32d a[10]; a[0] = x; is_eq(a[0],42.0); } { typedef int integer; typedef int INTEGER; integer i = 123; INTEGER j = 567; j = i; i = j; is_eq(i , 123); is_eq(j , 123); } double *d = (double *) 0; is_true(d == NULL); int *i = (int *) 0; is_true(i == NULL); float *f = (float *) 0; is_true(f == NULL); char *c = (char *) 0; is_true(c == NULL); double *d2 = 0; is_true(d2 == NULL); int *i2 = 0; is_true(i2 == NULL); float *f2 = 0; is_true(f2 == NULL); char *c2 = 0; is_true(c2 == NULL); diag("Calloc with type") { double *ddd = (double *)calloc(2,sizeof(double)); is_not_null(ddd); (void)(ddd); } { double *ddd; ddd = (double *)calloc(2,sizeof(double)); is_not_null(ddd); (void)(ddd); } diag("Type convertion from void* to ...") { void * ptr2; int tInt = 55; ptr2 = &tInt; is_eq(*(int*)ptr2, 55); double tDouble = -13; ptr2 = &tDouble; is_eq(*(double*)ptr2,-13); float tFloat = 67; is_eq(*(float *)(&tFloat),67); } diag("Type convertion from void* to ... in initialization") { long tLong = 556; void * ptr3 = &tLong; is_eq(*(long *) ptr3, 556); } char_overflow(); diag("Compare preprocessor with type") test_preprocessor(); diag("Typedef slice convertion") caststr(); diag("Compare with static array") test_static_array(); diag("Cast with compound assign operator") castbitwise(); diag("Cast pointer diff"); { pcre_uchar s[] = "abcd"; int b = 42; cast_pointer_diff(&s[0], &b); is_eq(b, 0); } diag("Cast array to slice"); { pcre_study_data sdata; sdata.start_bits[1] = 42; const pcre_study_data *study = &sdata; const pcre_uint8 *p = 0; p = study->start_bits; is_eq(p[1], 42); } done_testing(); } c2go-0.26.10/tests/code_quality/000077500000000000000000000000001410601753200163355ustar00rootroot00000000000000c2go-0.26.10/tests/code_quality/for.c000066400000000000000000000002341410601753200172660ustar00rootroot00000000000000void f1() { int i; for ( i = 0 ; i < 10 ; i++){;} } void f2() { int i; for ( i = 10 ; i > 0 ; i--){;} } void f3() { for( int i = 0; i< 10 ;i++){;} } c2go-0.26.10/tests/code_quality/for.expected.c000066400000000000000000000011531410601753200210670ustar00rootroot00000000000000/* Package main - transpiled by c2go version: v0.23.0 Berkelium 2018-04-27 If you have found any issues, please raise an issue at: https://github.com/elliotchance/c2go/ */ package code_quality // f1 - transpiled function from tests/code_quality/for.c:1 func f1() { var i int32 for i = int32(0); i < int32(10); i++ { } } // f2 - transpiled function from tests/code_quality/for.c:7 func f2() { var i int32 for i = int32(10); i > int32(0); i-- { } } // f3 - transpiled function from tests/code_quality/for.c:13 func f3() { { var i int32 = int32(0) for ; i < int32(10); i++ { } } } func init() { } c2go-0.26.10/tests/code_quality/generate.sh000077500000000000000000000011521410601753200204650ustar00rootroot00000000000000#!/bin/bash # # Run this script from / # to generate *.expected.c from *.c files # using the current c2go sources. # go build # Generate code quality Go code FILES='tests/code_quality/*.c' for file in $FILES do filename=$(basename "$file") ext="${filename#*.}" if [ "$ext" = "expected.c" ]; then continue fi echo "Processing $file file..." filename=${file%.*}".expected.c" ./c2go transpile -o="$filename" -p="code_quality" $file # Normalize transpiled from comments sed -i '' -E 's/^\/\/([^\/]*)(.*)tests\/code_quality\/(.*)$/\/\/\1tests\/code_quality\/\3/g' $filename done c2go-0.26.10/tests/code_quality/if.c000066400000000000000000000002311410601753200170730ustar00rootroot00000000000000void if_1() { int a = 5; int b = 2; int c = 4; if ( a > b ) { return; } else if ( c <= a) { a = 0; } (void)(a); (void)(b); (void)(c); } c2go-0.26.10/tests/code_quality/if.expected.c000066400000000000000000000007031410601753200206770ustar00rootroot00000000000000/* Package main - transpiled by c2go version: v0.23.0 Berkelium 2018-04-27 If you have found any issues, please raise an issue at: https://github.com/elliotchance/c2go/ */ package code_quality // if_1 - transpiled function from tests/code_quality/if.c:1 func if_1() { var a int32 = int32(5) var b int32 = int32(2) var c int32 = int32(4) if a > b { return } else if c <= a { a = int32(0) } _ = (a) _ = (b) _ = (c) } func init() { } c2go-0.26.10/tests/code_quality/operators.c000066400000000000000000000000671410601753200205220ustar00rootroot00000000000000void operators_equals() { int a,b,c,d; a=b=c=d=42; } c2go-0.26.10/tests/code_quality/operators.expected.c000066400000000000000000000006341410601753200223220ustar00rootroot00000000000000/* Package main - transpiled by c2go version: v0.23.0 Berkelium 2018-04-27 If you have found any issues, please raise an issue at: https://github.com/elliotchance/c2go/ */ package code_quality // operators_equals - transpiled function from tests/code_quality/operators.c:1 func operators_equals() { var a int32 var b int32 var c int32 var d int32 d = int32(42) c = d b = c a = b } func init() { } c2go-0.26.10/tests/code_quality/switch.c000066400000000000000000000004221410601753200200000ustar00rootroot00000000000000void switch_function() { int i = 34; switch (i) { case (0): case (1): return; case (2): (void)(i); return; case 3: { int c; return; } case 4: break; case 5: { break; } case 6: { } case 7: { int d; break; } } } c2go-0.26.10/tests/code_quality/switch.expected.c000066400000000000000000000012111410601753200215750ustar00rootroot00000000000000/* Package main - transpiled by c2go version: v0.23.0 Berkelium 2018-04-27 If you have found any issues, please raise an issue at: https://github.com/elliotchance/c2go/ */ package code_quality // switch_function - transpiled function from tests/code_quality/switch.c:1 func switch_function() { var i int32 = int32(34) switch i { case (int32(0)): fallthrough case (int32(1)): { return } case (int32(2)): { _ = (i) return } case int32(3): { var c int32 return } case int32(4): { } case int32(5): { } case int32(6): fallthrough case int32(7): { var d int32 break } } } func init() { } c2go-0.26.10/tests/comment/000077500000000000000000000000001410601753200153155ustar00rootroot00000000000000c2go-0.26.10/tests/comment/main.c000066400000000000000000000011751410601753200164110ustar00rootroot00000000000000// comment1 /* comment2 */ /* * comment3 */ void /* comment4 */ a /* comment5 */( /* comment6 */ int /* comment7 */ i /*comment8*/) // comment9 { // comment10 // comment11 (/* comment12 */ void /* comment13 */)/*comment14*/(/*comment15*/ i /*comment16 */)/*comment17*/; } // comment18 //comment19 void b //comment20 ( // comment21 )//comment22 { //comment23 //comment24 int i = 9; (void)(i); }//comment25 void /* comment26 */ main () { int i = 0; for ( i = 0 ; i < 5 ; i++) { if (i > 2) {/*comment27*/ a(i); } else { /* * * * // comment28 */ b(); } } } /* * comment29 * * * */ // comment30 c2go-0.26.10/tests/ctype.c000066400000000000000000000051761410601753200151540ustar00rootroot00000000000000// Tests for ctype.h. #include #include #include "tests.h" #define T is_true #define F is_false #define CTYPE(functionName, A, B, C, D, E, F, G, H) \ diag(#functionName); \ A(functionName('a')); \ B(functionName('B')); \ C(functionName('0')); \ D(functionName('*')); \ E(functionName('\0')); \ F(functionName(' ')); \ G(functionName('\n')); \ H(functionName('z')); // This is just helpful for alignment. #define _CTYPE CTYPE char *strnul = "this string has a \0 NUL"; char arrnul[] = "this string has a \0 NUL"; #define PRINTF_BOOL(v) { if(v) printf("T"); else printf("F"); } int main() { plan(104); // . Lower alpha (a) // | . Upper alpha (B) // | | . Digit (0) // | | | . Punctuation (*) // | | | | . NULL // | | | | | . Space // | | | | | | . New line // | | | | | | | . Non-hex digit (z) // v v v v v v v v _CTYPE(isalnum, T, T, T, F, F, F, F, T); _CTYPE(isalpha, T, T, F, F, F, F, F, T); _CTYPE(iscntrl, F, F, F, F, T, F, T, F); _CTYPE(isdigit, F, F, T, F, F, F, F, F); _CTYPE(isgraph, T, T, T, T, F, F, F, T); _CTYPE(islower, T, F, F, F, F, F, F, T); _CTYPE(isprint, T, T, T, T, F, T, F, T); _CTYPE(ispunct, F, F, F, T, F, F, F, F); _CTYPE(isspace, F, F, F, F, F, T, T, F); _CTYPE(isupper, F, T, F, F, F, F, F, F); CTYPE(isxdigit, T, T, T, F, F, F, F, F); diag("char properties for characters 0-255:"); for(int i=0; i<256; i++) { printf("%x: ", i); PRINTF_BOOL(isalnum(i)); PRINTF_BOOL(isalpha(i)); PRINTF_BOOL(iscntrl(i)); PRINTF_BOOL(isdigit(i)); PRINTF_BOOL(isgraph(i)); PRINTF_BOOL(islower(i)); PRINTF_BOOL(isprint(i)); PRINTF_BOOL(ispunct(i)); PRINTF_BOOL(isspace(i)); PRINTF_BOOL(isupper(i)); PRINTF_BOOL(isxdigit(i)); printf("\n"); } diag("tolower"); is_eq(tolower('a'), 'a'); is_eq(tolower('B'), 'b'); is_eq(tolower('0'), '0'); is_eq(tolower('*'), '*'); is_eq(tolower('\0'), '\0'); is_eq(tolower(' '), ' '); is_eq(tolower('\n'), '\n'); is_eq(tolower('z'), 'z'); diag("toupper"); is_eq(toupper('a'), 'A'); is_eq(toupper('B'), 'B'); is_eq(toupper('0'), '0'); is_eq(toupper('*'), '*'); is_eq(toupper('\0'), '\0'); is_eq(toupper(' '), ' '); is_eq(toupper('\n'), '\n'); is_eq(toupper('z'), 'Z'); done_testing(); } c2go-0.26.10/tests/do.c000066400000000000000000000010601410601753200144160ustar00rootroot00000000000000#include #include "tests.h" int main() { plan(7); int i = 0; // There will be 4 checks in the first loop. do { pass("%s", "first do statement"); i = i + 1; } while( i < 4 ); // Only one check in the second loop. i = 0; do { i++; if(i < 3) continue; pass("%s", "second do statement"); } while(i < 3); diag("check while"); i = 1000; do { i--; if (i < 10) { break; } } while ((i /= 10) > 0); is_eq( i , 8 ); diag("do without CompoundStmt"); int s = 1; do s++; while(s < 10); is_eq(s , 10); done_testing(); } c2go-0.26.10/tests/enum.c000066400000000000000000000035431410601753200147700ustar00rootroot00000000000000#include #include "tests.h" /* Text */ enum number{zero, one, two, three}; /** * Text */ enum { _ISupper = ((0) < 8 ? ((1 << (0)) << 8) : ((1 << (0)) >> 8)), _ISalnum = ((11) < 8 ? ((1 << (11)) << 8) : ((1 << (11)) >> 8)) }; /** Text */ enum year{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; // Text enum State {Working = 1, Failed = 0, Freezed = 0}; // Text // Text enum day {sunday = 1, monday, tuesday = 5, wednesday, thursday = 10, friday, saturday}; enum state {WORKING = 0, FAILED, FREEZED}; enum state currState = 2; enum state FindState() {return currState;} enum { FLY , JUMP }; /// TYPEDEF typedef enum { a, b, c } T_ENUM; /** * Text */ typedef enum e_strategy {RANDOM, IMMEDIATE = 5, SEARCH} strategy; enum { ESC_A = 1, ESC_d }; // main function int main() { plan(30); // step 1 enum number n; n = two; is_eq(two ,2); is_eq(n ,2); // step 2 is_eq(_ISupper ,256); is_eq(_ISalnum ,8 ); // step 3 for (int i=Jan; i < Feb; i++){ is_eq(i, Jan); } // step 4 is_eq( Working , 1); is_eq( Failed , 0); is_eq( Freezed , 0); // step 5 enum day d = thursday; is_eq( d , 10); // step 6 is_eq( sunday , 1); is_eq( monday , 2); is_eq( tuesday , 5); is_eq( wednesday , 6); is_eq( thursday , 10); is_eq( friday , 11); is_eq( saturday , 12); // step 7 is_eq( FindState() , FREEZED); // step T_ENUM cc = a; is_eq( cc , a ); cc = c; is_eq( cc , c ); cc = (T_ENUM)(1); is_eq( cc , b ); // step strategy str = RANDOM; is_eq( str , RANDOM ); enum e_strategy e_str = RANDOM; is_eq( e_str, RANDOM ); is_eq( str , e_str ); is_eq(IMMEDIATE , 5); is_eq(SEARCH , 6); // step is_eq( FLY , 0 ); is_eq( JUMP , 1 ); is_eq(ESC_d, 2); diag("sizeof") is_eq(sizeof(JUMP ),sizeof(int)); is_eq(sizeof(Jan ),sizeof(int)); done_testing(); } c2go-0.26.10/tests/exit.c000066400000000000000000000002261410601753200147700ustar00rootroot00000000000000#include #include "tests.h" int main() { plan(0); exit(123); // done_testing() is not needed because this is unreachable. } c2go-0.26.10/tests/exit_status.c000066400000000000000000000002651410601753200163760ustar00rootroot00000000000000#include #include "tests.h" int main() { plan(0); // There is no done_testing() becuase we want to return an error code without // checks that fail. return 1; } c2go-0.26.10/tests/externalHeader/000077500000000000000000000000001410601753200166065ustar00rootroot00000000000000c2go-0.26.10/tests/externalHeader/include/000077500000000000000000000000001410601753200202315ustar00rootroot00000000000000c2go-0.26.10/tests/externalHeader/include/head.h000066400000000000000000000002551410601753200213050ustar00rootroot00000000000000#include // Checking case with header on another folder then main function void print(){ // tests that functions can be declared in the header. printf("42"); } c2go-0.26.10/tests/externalHeader/main/000077500000000000000000000000001410601753200175325ustar00rootroot00000000000000c2go-0.26.10/tests/externalHeader/main/main.c000066400000000000000000000001701410601753200206200ustar00rootroot00000000000000#include "head.h" // Checking case with header on another folder then main function int main(){ print(); return 0; } c2go-0.26.10/tests/for.c000066400000000000000000000057741410601753200146220ustar00rootroot00000000000000#include #include "tests.h" int main() { plan(61); int i = 0; diag("Missing init"); for (; i < 3; i++) pass("%d", i); diag("CompountStmt"); for (i = 0; i < 3; i++) { pass("%d", i); } diag("Not CompountStmt"); for (i = 0; i < 3; i++) pass("%d", i); diag("Infinite loop"); int j = 0; for (;;) { pass("%d", j); j++; if (j > 3) break; } diag("continue"); i = 0; j = 0; for (;;) { pass("%d %d", i, j); i++; if (i < 3) continue; j++; if (j > 3) break; } diag("big initialization 1"); for ( i = 0, j = 0 ; i < 3 ; i++){ pass("%d %d", i, j); } diag("big initialization 2"); for ( i = 0, j = 0 ; i < 3 ; ){ pass("%d %d", i, j); i++; j++; } diag("big increment"); i = 0; j = 0; for (;i < 3;i++,j++){ pass("%d %d", i, j); } diag("big condition"); i = -1; j = 0; for(;i++,j<3;){ pass("%d %d", i, j); j++; } diag("Without body and with 2 and more increments"); for(i = 0, j = 0; i < 2; j++,i++); pass("%d",i); diag("Without body and with 2 and more conditions"); for(i = 0, j = 0; j++,i++,i < 2; ); pass("%d",i); diag("initialization inside for"); for(int h = 0;h < 3; h++) pass("%d",h); diag("double initialization inside for"); for(int f = 0 , g = 0;g < 2 || f < 2; g++, f++){ pass("%d",f); pass("%d",g); } { diag("double initialization inside for with double for"); for(int ef = 0 , eg = 0;eg < 2 || ef < 2; eg++, ef++){ pass("%d",ef); pass("%d",eg); } for(int ef = 0 , eg = 0;eg < 2 || ef < 2; eg++, ef++){ pass("%d",ef); pass("%d",eg); } } diag("NULL in for"); int nn = 0; for (; NULL ; nn ++){ if (nn > 2) { break; } } is_eq( nn , 0 ); diag("! NULL in for"); int nn2 = 0; for (; !NULL ; nn2 ++){ if (nn2 > 2) { break; } } is_eq( nn2 , 3 ); diag("for with specific body"); { double vars = 42.0; for(int s = 0;s<1;s++) vars ++; is_eq(vars,43.0); } { double vars = 42.0; for(int s = 0;s<1;s++) vars += 1.0; is_eq(vars,43.0); } { double vars = 42.0; int X,Y; for(X = 0, Y = 0; X < 1;X++,Y++) vars += 1.0; is_eq(vars,43.0); } { double vars = 42.0; for(int s = 0;s<1;s++) vars = vars + 1.0; is_eq(vars,43.0); } { double vars = 42.0; int X,Y; for(X = 0, Y = 0; X < 1;X++,Y++) vars = vars + 1.0; is_eq(vars,43.0); } { int X,Y; for(X = 0, Y = 0; X < 1;X++,Y++) X += Y; pass("ok"); } { int X,Y; for(X = 0, Y = 0; X < 1;X++,Y++) X = X + Y; pass("ok"); } diag("increment --"); for (i = 3; i >= 1; i--) pass("%d", i); diag("increment -= 3"); for (i = 3; i >= 1; i-=3) pass("%d", i); done_testing(); } c2go-0.26.10/tests/function.c000066400000000000000000000101351410601753200156440ustar00rootroot00000000000000#include #include "tests.h" void my_function(); int i = 40; void function(){ i += 2; } void function2(){ i += 8; } int (*f)(int, int); int add(int a, int b) { return a + b; } int mul(int a, int b) { return a * b; } double (*f2)(int, float, double); double add2 (int a, float b, double c) { return c+a+b; } double mul2 (int a, float b, double c) { return a*b*c; } double action(double (*F)(int,float,double)){ return F(2,3,4); } // Go keywords in C function int chan() {return 42;} int defer() {return 42;} int fallthrough(){return 42;} int func() {return 42;} int go() {return 42;} int import() {return 42;} int interface() {return 42;} int map() {return 42;} int package() {return 42;} int range() {return 42;} int select() {return 42;} int type() {return 42;} int var() {return 42;} int _() {return 42;} int init() {return 42;} int len() {return 42;} int copy() {return 42;} int fmt() {return 42;} int cap() {return 42;} void exit2(int t){ (void)(t); } void empty_return(){ int i = 0; (void)(i); exit2(-1); } int empty_return_int(int a){ if ( a > 0 ){ return 1;} else { exit2(-1);} } int empty_return_int2(int *a){ if (*a > 0 ){ return 1;} else { exit2(-1);} } double empty_return_double(double a){ if ( a > 0.0 ){ return 1.0;} else { exit2(-1);} } double empty_return_double2(double*a){ if (*a > 0.0 ){ return 1.0;} else { exit2(-1);} } typedef struct RE RE; struct RE { int re; }; RE empty_return_struct(int a){ if ( a > 0.0 ){ RE r; r.re = 1; return r;} else { exit2(-1);} } RE* empty_return_struct2(int a){ if ( a > 0.0 ){ RE r; r.re = 1; return &r;} else { exit2(-1);} } typedef int (* operators)(int a,int b); int call_a_func(operators call_this) { int output = call_this(5, 8); return output; } long tolower (int a, int b) { return (long)(a+b);} long toupper (int a, int b) { return (long)(a+b);} int main() { plan(48); pass("%s", "Main function."); my_function(); pass("%s", "Back in function main."); diag("pointer on function. Part 1") void * a = NULL; is_null(a); a = function; is_not_null(a); void(*t)(void) = a; is_not_null(t); t(); is_eq(i,42); t = function2; is_not_null(t); t(); is_eq(i,50); diag("pointer on function. Part 2") f = add; int i = f(3,4); is_eq(i,7); f = mul; int j = f(3,4); is_eq(j,12); if( f(2,3) == 6 ){ pass("Ok") } diag("pointer on function. Part 3") { f2 = add2; double temp_data; temp_data = f2(4,2,3); is_eq(temp_data,9); f2 = mul2; is_eq(f2(4,2,3),24); double ttt = f2(1,1,1); is_eq(ttt,1); if(add2(2,3,1) == 6.0){ pass("Ok") } } diag("Not allowable function name for Go") is_eq( chan() , 42); is_eq( defer() , 42); is_eq( fallthrough(), 42); is_eq( func() , 42); is_eq( go() , 42); is_eq( import() , 42); is_eq( interface() , 42); is_eq( map() , 42); is_eq( package() , 42); is_eq( range() , 42); is_eq( select() , 42); is_eq( type() , 42); is_eq( var() , 42); is_eq( _() , 42); is_eq( init() , 42); is_eq( len() , 42); is_eq( copy() , 42); is_eq( fmt() , 42); is_eq( cap() , 42); diag("Function pointer inside function") is_eq(action(add2), add2(2,3,4)); is_eq(action(mul2), mul2(2,3,4)); diag("Function with empty return") { empty_return(); pass("ok"); } { empty_return_int(2); pass("ok"); } { int Y = 6; is_eq(empty_return_int2(&Y),1); } { double Y = 6; is_eq(empty_return_double(Y),1); } { double Y = 6; is_eq(empty_return_double2(&Y),1); } { is_eq((empty_return_struct(6)).re,1); } { is_eq((*(empty_return_struct2(6))).re,1); } diag("typedef function"); { int result = call_a_func(&mul); is_eq(result,40); } { is_eq(call_a_func(&mul),40); } diag("function name like in CSTD"); { is_eq(tolower(34,52),86); is_eq(toupper(34,52),86); } done_testing(); } void my_function() { pass("%s", "Welcome to my function. Feel at home."); } c2go-0.26.10/tests/getchar.c000066400000000000000000000003301410601753200154300ustar00rootroot00000000000000// getchar() needs to be in it's own file because it takes input from stdin. #include #include "tests.h" int main() { plan(1); int c; c = getchar(); is_eq(c, '7'); done_testing(); } c2go-0.26.10/tests/goto.c000066400000000000000000000015351410601753200147730ustar00rootroot00000000000000#include #include #include "tests.h" #define START_TEST(t) \ diag(#t); \ test_##t(); void test_goto1() { int i = 0; mylabel: i++; if (i > 5) { fail("Parameter i = %d, but expect 1",i); return; } if (i == 1) { goto mylabel; } is_eq(i, 2); } void test_goto2() { int i = 0; int j = 0; mylabel: i++, j++; if (j > 5) { fail("Parameter j = %d, but expect 1",j); return; } if (i == 1) { goto mylabel; } is_eq(i, 2); is_eq(j, 2); } void test_goto_stmt() { int i = 0, j = 0; mylabel: for (j=0; j<5; j++) i++; if (i < 15) { goto mylabel; } is_eq(i, 15); } int main() { plan(4); START_TEST(goto1) START_TEST(goto2) START_TEST(goto_stmt) done_testing(); } c2go-0.26.10/tests/if.c000066400000000000000000000024631410601753200144220ustar00rootroot00000000000000#include #include "tests.h" int d(int v){ return 2*v; } void compare_pointers() { char * str = "aaaaaaaaaa"; char * a = &str[2]; char * b = &str[3]; int t = a < b; is_true(t); b = &str[1]; t = a > b; is_true(t); t = a == b; is_false(t); t = a < b; is_false(t); b = &str[2]; t = a == b; is_true(t); t = a < b; is_false(t); t = a <= b; is_true(t); t = a >= b; is_true(t); t = a == 0; is_false(t); } int main() { plan(16); int x = 1; // Without else if (x == 1) pass("%s", "x is equal to one"); if (x == 1){ pass("%s", "x is equal to one"); } // With else if (x != 1){ fail("%s", "x is not equal to one"); } else { pass("%s", "x is equal to one"); } if ( NULL) { fail("%s", "NULL is zero"); } else { pass("%s", "NULL is not zero"); } if ( ! NULL) { pass("%s", "Invert : ! NULL is zero"); } else { fail("%s", "Invert : ! NULL is not zero"); } diag("Operation inside function") int ii = 5; if ((ii = d(ii)) != (-1)){ is_eq(ii,10) } diag("if - else"); { int a = 10; int b = 5 ; int c = 0 ; if ( a < b ) { } else if (b > c) { pass("ok"); } } diag("Pointer comparisons"); compare_pointers(); done_testing(); } c2go-0.26.10/tests/math.c000066400000000000000000000326741410601753200147640ustar00rootroot00000000000000// Test for math.h. #include #include #include "tests.h" #define PI 3.14159265 #define IS_NAN -2147483648 unsigned long long ullmax = 18446744073709551615ull; int main() { plan(359); // Note: There are some tests that must be disabled because they return // different values under different compilers. See the comment surrounding the // disabled() tests for more information. // Test constants diag("constants"); is_eq(M_E, 2.71828182845904509080); is_eq(M_LOG2E, 1.44269504088896338700); is_eq(M_LOG10E, 0.43429448190325181667); is_eq(M_LN2, 0.69314718055994528623); is_eq(M_LN10, 2.30258509299404590109); is_eq(M_PI, 3.14159265358979311600); is_eq(M_PI_2, 1.57079632679489655800); is_eq(M_PI_4, 0.78539816339744827900); is_eq(M_1_PI, 0.31830988618379069122); is_eq(M_2_PI, 0.63661977236758138243); is_eq(M_2_SQRTPI, 1.12837916709551255856); is_eq(M_SQRT2, 1.41421356237309514547); is_eq(M_SQRT1_2, 0.70710678118654757274); // Each of the tests are against these values: // // * Simple: 0, 1, -1, 0.5 // * Large and small: 1.23e300, -1.23e-300 // * Constants: M_PI, M_E // * Special: INFINITY, -INFINITY, NAN diag("acos"); is_eq(acos(0), 1.57079632679489655800); is_eq(acos(1), 0); is_eq(acos(-1), M_PI); is_eq(acos(0.5), 1.04719755119659763132); is_nan(acos(1.23e300)); is_eq(acos(-1.23e-300), 1.57079632679489655800); is_nan(acos(M_PI)); is_nan(acos(M_E)); is_nan(acos(INFINITY)); is_nan(acos(-INFINITY)); is_nan(acos(NAN)); diag("asin"); is_eq(asin(0), 0); is_eq(asin(1), 1.57079632679489655800); is_eq(asin(-1), -1.57079632679489655800); is_eq(asin(0.5), 0.52359877559829881566); is_nan(asin(1.23e300)); is_negzero(asin(-1.23e-300)); is_nan(asin(M_PI)); is_nan(asin(M_E)); is_nan(asin(INFINITY)); is_nan(asin(-INFINITY)); is_nan(asin(NAN)); diag("atan"); is_eq(atan(0), 0); is_eq(atan(1), 0.78539816339744827900); is_eq(atan(-1), -0.78539816339744827900); is_eq(atan(0.5), 0.46364760900080614903); is_eq(atan(1.23e300), 1.57079632679489655800); is_negzero(atan(-1.23e-300)); is_eq(atan(M_PI), 1.26262725567891154199); is_eq(atan(M_E), 1.21828290501727765083); is_eq(atan(INFINITY), 1.57079632679489655800); is_eq(atan(-INFINITY), -1.57079632679489655800); is_nan(atan(NAN)); diag("atan2"); // atan2(x, 0) is_eq(atan2(0, 0), 0); is_eq(atan2(1, 0), 1.57079632679489655800); is_eq(atan2(-1, 0), -1.57079632679489655800); is_eq(atan2(0.5, 0), 1.57079632679489655800); is_eq(atan2(1.23e300, 0), 1.57079632679489655800); is_negzero(atan2(-1.23e-300, 0)); is_eq(atan2(M_PI, 0), 1.57079632679489655800); is_eq(atan2(M_E, 0), 1.57079632679489655800); is_eq(atan2(INFINITY, 0), 1.57079632679489655800); is_eq(atan2(-INFINITY, 0), -1.57079632679489655800); is_nan(atan2(NAN, 0)); // atan2(x, 1) is_eq(atan2(0, 1), 0); is_eq(atan2(1, 1), 0.78539816339744827900); is_eq(atan2(-1, 1), -0.78539816339744827900); is_eq(atan2(0.5, 1), 0.46364760900080609352); is_eq(atan2(1.23e300, 1), 1.57079632679489655800); is_negzero(atan2(-1.23e-300, 1)); is_eq(atan2(M_PI, 1), 1.262627255678911764); is_eq(atan2(M_E, 1), 1.2182829050172776508); is_eq(atan2(INFINITY, 1), 1.57079632679489655800); is_eq(atan2(-INFINITY, 1), -1.57079632679489655800); is_nan(atan2(NAN, 1)); // atan2(x, INFINITY) is_eq(atan2(0, INFINITY), 0); is_eq(atan2(1, INFINITY), 0); is_negzero(atan2(-1, INFINITY)); is_eq(atan2(0.5, INFINITY), 0); is_eq(atan2(1.23e300, INFINITY), 0); is_negzero(atan2(-1.23e-300, INFINITY)); is_eq(atan2(M_PI, INFINITY), 0); is_eq(atan2(M_E, INFINITY), 0); is_eq(atan2(INFINITY, INFINITY), 0.78539816339744827900); is_eq(atan2(-INFINITY, INFINITY), -0.78539816339744827900); is_nan(atan2(NAN, INFINITY)); // atan2(x, -INFINITY) is_eq(atan2(0, -INFINITY), M_PI); is_eq(atan2(1, -INFINITY), M_PI); is_negzero(atan2(-1, -INFINITY)); is_eq(atan2(0.5, -INFINITY), M_PI); is_eq(atan2(1.23e300, -INFINITY), M_PI); is_negzero(atan2(-1.23e-300, -INFINITY)); is_eq(atan2(M_PI, -INFINITY), M_PI); is_eq(atan2(M_E, -INFINITY), M_PI); is_eq(atan2(INFINITY, -INFINITY), 2.356194490192344837); is_eq(atan2(-INFINITY, -INFINITY), -2.356194490192344837); is_nan(atan2(NAN, -INFINITY)); // atan2(x, NAN) is_nan(atan2(0, NAN)); is_nan(atan2(1, NAN)); is_nan(atan2(-1, NAN)); is_nan(atan2(0.5, NAN)); is_nan(atan2(1.23e300, NAN)); is_nan(atan2(-1.23e-300, NAN)); is_nan(atan2(M_PI, NAN)); is_nan(atan2(M_E, NAN)); is_nan(atan2(INFINITY, NAN)); is_nan(atan2(-INFINITY, NAN)); is_nan(atan2(NAN, NAN)); diag("ceil"); is_eq(ceil(0), 0); is_eq(ceil(1), 1); is_eq(ceil(-1), -1); is_eq(ceil(0.5), 1); is_eq(ceil(1.23e300), 1.23e300); is_eq(ceil(-1.23e-300), 0); is_eq(ceil(M_PI), 4); is_eq(ceil(M_E), 3); is_inf(ceil(INFINITY), 1); is_inf(ceil(-INFINITY), -1); is_nan(ceil(NAN)); diag("cos"); is_eq(cos(0), 1); is_eq(cos(1), 0.54030230586813976501); is_eq(cos(-1), 0.54030230586813976501); is_eq(cos(0.5), 0.87758256189037275874); // https://github.com/golang/go/issues/20539 disabled(is_eq(cos(1.23e300), 0.251533)); is_eq(cos(-1.23e-300), 1); is_eq(cos(M_PI), -1); is_eq(cos(M_E), -0.91173391478696508283); is_nan(cos(INFINITY)); is_nan(cos(-INFINITY)); is_nan(cos(NAN)); diag("cosh"); is_eq(cosh(0), 1); is_eq(cosh(1), 1.5430806348152437124); is_eq(cosh(-1), 1.5430806348152437124); is_eq(cosh(0.5), 1.1276259652063806982); // https://github.com/golang/go/issues/20539 disabled(is_eq(cosh(1.23e300), 1)); is_eq(cosh(-1.23e-300), 1); is_eq(cosh(M_PI), 11.591953275521518663); is_eq(cosh(M_E), 7.6101251386622870143); is_inf(cosh(INFINITY), 1); is_inf(cosh(-INFINITY), 1); is_nan(cosh(NAN)); diag("exp"); is_eq(exp(0), 1); is_eq(exp(1), 2.7182818284590450908); is_eq(exp(-1), 0.36787944117144233402); is_eq(exp(0.5), 1.6487212707001281942); // https://github.com/golang/go/issues/20539 disabled(is_inf(exp(1.23e300), 1)); is_eq(exp(-1.23e-300), 1); is_eq(exp(M_PI), 23.140692632779266802); is_eq(exp(M_E), 15.154262241479262485); is_inf(exp(INFINITY), 1); is_eq(exp(-INFINITY), 0); is_nan(exp(NAN)); diag("fabs"); is_eq(fabs(0), 0); is_eq(fabs(1), 1); is_eq(fabs(-1), 1); is_eq(fabs(0.5), 0.5); is_eq(fabs(1.23e300), 1.23e300); is_eq(fabs(-1.23e-300), 1.23e-300); is_eq(fabs(M_PI), M_PI); is_eq(fabs(M_E), M_E); is_inf(fabs(INFINITY), 1); is_inf(fabs(-INFINITY), 1); is_nan(fabs(NAN)); diag("floor"); is_eq(floor(0), 0); is_eq(floor(1), 1); is_eq(floor(-1), -1); is_eq(floor(0.5), 0); is_eq(floor(1.23e300), 1.23e300); is_eq(floor(-1.23e-300), -1); is_eq(floor(M_PI), 3); is_eq(floor(M_E), 2); is_inf(floor(INFINITY), 1); is_inf(floor(-INFINITY), -1); is_nan(floor(NAN)); diag("fmod"); // fmod(x, 0) is_nan(fmod(0, 0)); is_nan(fmod(1, 0)); is_nan(fmod(-1, 0)); is_nan(fmod(0.5, 0)); is_nan(fmod(1.23e300, 0)); is_nan(fmod(-1.23e-300, 0)); is_nan(fmod(M_PI, 0)); is_nan(fmod(M_E, 0)); is_nan(fmod(INFINITY, 0)); is_nan(fmod(-INFINITY, 0)); is_nan(fmod(NAN, 0)); // fmod(x, 0.5) is_eq(fmod(0, 0.5), 0); is_eq(fmod(1, 0.5), 0); is_negzero(fmod(-1, 0.5)); is_eq(fmod(0.5, 0.5), 0); is_eq(fmod(1.23e300, 0.5), 0); is_negzero(fmod(-1.23e-300, 0.5)); is_eq(fmod(M_PI, 0.5), M_PI - 3); is_eq(fmod(M_E, 0.5), M_E - 2.5); is_nan(fmod(INFINITY, 0.5)); is_nan(fmod(-INFINITY, 0.5)); is_nan(fmod(NAN, 0.5)); // fmod(x, INFINITY) is_eq(fmod(0, INFINITY), 0); is_eq(fmod(1, INFINITY), 1); is_negzero(fmod(-1, INFINITY)); is_eq(fmod(0.5, INFINITY), 0.5); is_eq(fmod(1.23e300, INFINITY), 1.23e300); is_negzero(fmod(-1.23e-300, INFINITY)); is_eq(fmod(M_PI, INFINITY), M_PI); is_eq(fmod(M_E, INFINITY), M_E); is_nan(fmod(INFINITY, INFINITY)); is_nan(fmod(-INFINITY, INFINITY)); is_nan(fmod(NAN, INFINITY)); // fmod(x, -INFINITY) is_eq(fmod(0, -INFINITY), 0); is_eq(fmod(1, -INFINITY), 1); is_negzero(fmod(-1, -INFINITY)); is_eq(fmod(0.5, -INFINITY), 0.5); is_eq(fmod(1.23e300, -INFINITY), 1.23e300); is_negzero(fmod(-1.23e-300, -INFINITY)); is_eq(fmod(M_PI, -INFINITY), M_PI); is_eq(fmod(M_E, -INFINITY), M_E); is_nan(fmod(INFINITY, -INFINITY)); is_nan(fmod(-INFINITY, -INFINITY)); is_nan(fmod(NAN, -INFINITY)); // fmod(x, NAN) is_nan(fmod(0, NAN)); is_nan(fmod(1, NAN)); is_nan(fmod(-1, NAN)); is_nan(fmod(0.5, NAN)); is_nan(fmod(1.23e300, NAN)); is_nan(fmod(-1.23e-300, NAN)); is_nan(fmod(M_PI, NAN)); is_nan(fmod(M_E, NAN)); is_nan(fmod(INFINITY, NAN)); is_nan(fmod(-INFINITY, NAN)); is_nan(fmod(NAN, NAN)); diag("ldexp"); is_eq(ldexp(0, 2), 0); is_eq(ldexp(1, 2), 4); is_eq(ldexp(-1, 2), -4); is_eq(ldexp(0.5, 2), 2); is_eq(ldexp(1.23e300, 2), 4.92e300); is_negzero(ldexp(-1.23e-300, 2)); is_eq(ldexp(M_PI, 2), 12.56637061435917246399); is_eq(ldexp(M_E, 2), 10.87312731383618036318); is_inf(ldexp(INFINITY, 2), 1); is_inf(ldexp(-INFINITY, 2), -1); is_nan(ldexp(NAN, 2)); diag("log"); is_inf(log(0), -1); is_eq(log(1), 0); is_nan(log(-1)); is_eq(log(0.5), -0.69314718055994528623); is_eq(log(1.23e300), 690.98254206759804674221); is_nan(log(-1.23e-300)); is_eq(log(M_PI), 1.14472988584940016388); is_eq(log(M_E), 1); is_inf(log(INFINITY), 1); is_nan(log(-INFINITY)); is_nan(log(NAN)); diag("log10"); is_inf(log10(0), -1); is_eq(log10(1), 0); is_nan(log10(-1)); is_eq(log10(0.5), -0.30102999566398119802); is_eq(log10(1.23e300), 300.08990511143940693728); is_nan(log10(-1.23e-300)); is_eq(log10(M_PI), 0.49714987269413385418); is_eq(log10(M_E), 0.43429448190325181667); is_inf(log10(INFINITY), 1); is_nan(log10(-INFINITY)); is_nan(log10(NAN)); diag("pow"); // pow(x, 0) is_eq(pow(0, 0), 1); is_eq(pow(1, 0), 1); is_eq(pow(-1, 0), 1); is_eq(pow(0.5, 0), 1); is_eq(pow(1.23e300, 0), 1); is_eq(pow(-1.23e-300, 0), 1); is_eq(pow(M_PI, 0), 1); is_eq(pow(M_E, 0), 1); is_eq(pow(INFINITY, 0), 1); is_eq(pow(-INFINITY, 0), 1); is_eq(pow(NAN, 0), 1); // pow(x, M_PI) is_eq(pow(0, M_PI), 0); is_eq(pow(1, M_PI), 1); is_nan(pow(-1, M_PI)); is_eq(pow(0.5, M_PI), 0.11331473229676088110); is_inf(pow(1.23e300, M_PI), 1); is_nan(pow(-1.23e-300, M_PI)); is_eq(pow(M_PI, M_PI), 36.46215960720790150162); is_eq(pow(M_E, M_PI), 23.14069263277926324918); is_inf(pow(INFINITY, M_PI), 1); is_inf(pow(-INFINITY, M_PI), 1); is_nan(pow(NAN, M_PI)); // pow(x, INFINITY) is_eq(pow(0, INFINITY), 0); is_eq(pow(1, INFINITY), 1); is_eq(pow(-1, INFINITY), 1); is_eq(pow(0.5, INFINITY), 0); is_inf(pow(1.23e300, INFINITY), 1); is_eq(pow(-1.23e-300, INFINITY), 0); is_inf(pow(M_PI, INFINITY), 1); is_inf(pow(M_E, INFINITY), 1); is_inf(pow(INFINITY, INFINITY), 1); is_inf(pow(-INFINITY, INFINITY), 1); is_nan(pow(NAN, INFINITY)); // pow(x, -INFINITY) is_inf(pow(0, -INFINITY), 1); is_eq(pow(1, -INFINITY), 1); is_eq(pow(-1, -INFINITY), 1); is_inf(pow(0.5, -INFINITY), 1); is_eq(pow(1.23e300, -INFINITY), 0); is_inf(pow(-1.23e-300, -INFINITY), 1); is_eq(pow(M_PI, -INFINITY), 0); is_eq(pow(M_E, -INFINITY), 0); is_eq(pow(INFINITY, -INFINITY), 0); is_eq(pow(-INFINITY, -INFINITY), 0); is_nan(pow(NAN, -INFINITY)); // pow(x, NAN) is_nan(pow(0, NAN)); is_eq(pow(1, NAN), 1); is_nan(pow(-1, NAN)); is_nan(pow(0.5, NAN)); is_nan(pow(1.23e300, NAN)); is_nan(pow(-1.23e-300, NAN)); is_nan(pow(M_PI, NAN)); is_nan(pow(M_E, NAN)); is_nan(pow(INFINITY, NAN)); is_nan(pow(-INFINITY, NAN)); is_nan(pow(NAN, NAN)); diag("sin"); is_eq(sin(0), 0); is_eq(sin(1), 0.84147098480789650488); is_eq(sin(-1), -0.84147098480789650488); is_eq(sin(0.5), 0.47942553860420300538); // https://github.com/golang/go/issues/20539 disabled(is_eq(sin(1.23e300), 0.967849)); is_negzero(sin(-1.23e-300)); is_eq(sin(M_PI), 0); is_eq(sin(M_E), 0.41078129050290879132); is_nan(sin(INFINITY)); is_nan(sin(-INFINITY)); is_nan(sin(NAN)); diag("sinh"); is_eq(sinh(0), 0); is_eq(sinh(1), 1.1752011936438013784); is_eq(sinh(-1), -1.1752011936438013784); is_eq(sinh(0.5), 0.52109530549374738495); // https://github.com/golang/go/issues/20539 disabled(is_eq(sinh(1.23e300), 1)); is_negzero(sinh(-1.23e-300)); is_eq(sinh(M_PI), 11.548739357257746363); is_eq(sinh(M_E), 7.5441371028169745827); is_inf(sinh(INFINITY), 1); is_inf(sinh(-INFINITY), -1); is_nan(sinh(NAN)); diag("sqrt"); is_eq(sqrt(0), 0); is_eq(sqrt(1), 1); is_nan(sqrt(-1)); is_eq(sqrt(0.5), 0.70710678118654757274); is_eq(sqrt(1.23e300), 1.1090536506409417761e150); is_nan(sqrt(-1.23e-300)); is_eq(sqrt(M_PI), 1.77245385090551588192); is_eq(sqrt(M_E), 1.64872127070012819416); is_inf(sqrt(INFINITY), 1); is_nan(sqrt(-INFINITY)); is_nan(sqrt(NAN)); diag("tan"); is_eq(tan(0), 0); is_eq(tan(1), 1.55740772465490207033); is_eq(tan(-1), -1.55740772465490207033); is_eq(tan(0.5), 0.54630248984379048416); // https://github.com/golang/go/issues/20539 disabled(is_eq(tan(1.23e300), 3.847798)); is_negzero(tan(-1.23e-300)); is_eq(tan(M_PI), 0); is_eq(tan(M_E), -0.45054953406980763342); is_nan(tan(INFINITY)); is_nan(tan(-INFINITY)); is_nan(tan(NAN)); diag("tanh"); is_eq(tanh(0), 0); is_eq(tanh(1), 0.76159415595576485103); is_eq(tanh(-1), -0.76159415595576485103); is_eq(tanh(0.5), 0.46211715726000973659); is_eq(tanh(1.23e300), 1); is_negzero(tanh(-1.23e-300)); is_eq(tanh(M_PI), 0.99627207622074998028); is_eq(tanh(M_E), 0.99132891580059978587); is_eq(tanh(INFINITY), 1); is_eq(tanh(-INFINITY), -1); is_nan(tanh(NAN)); done_testing(); } c2go-0.26.10/tests/multi-struct/000077500000000000000000000000001410601753200163275ustar00rootroot00000000000000c2go-0.26.10/tests/multi-struct/main.c000066400000000000000000000002371410601753200174210ustar00rootroot00000000000000#include #include "types.h" int main() { mystery m; m.answer = 42; type* t = to_type(m); say_type(t); free(t); return 0; } c2go-0.26.10/tests/multi-struct/types.c000066400000000000000000000004541410601753200176420ustar00rootroot00000000000000#include #include #include "types.h" struct real_type { unsigned int real_answer; }; void say_type(type *t) { printf("%d\n", t->real_answer); } type* to_type(mystery m) { type *ret = (type*) malloc(sizeof(type)); ret->real_answer = m.answer; return ret; } c2go-0.26.10/tests/multi-struct/types.h000066400000000000000000000004711410601753200176460ustar00rootroot00000000000000#ifndef HEADER #define HEADER struct real_type; typedef struct real_type type; typedef struct mystery { unsigned int answer; } mystery; // Forward-declared prototypes that are defined in one of our other C files. void say_type(type *t); // types.c type* to_type(mystery m); // types.c #endif /* HEADER */ c2go-0.26.10/tests/multi/000077500000000000000000000000001410601753200150055ustar00rootroot00000000000000c2go-0.26.10/tests/multi/err.h000066400000000000000000000000741410601753200157470ustar00rootroot00000000000000#include void ERROR_FUNC(){ printf("ERROR!"); } c2go-0.26.10/tests/multi/header.h000066400000000000000000000007411410601753200164100ustar00rootroot00000000000000#include // This header file is included by multiple C files. Make sure the preprocessor // is working correctly by not declaring duplicates. #ifndef HEADER #define HEADER // Headers usually do not contain whole functions, but we want to make sure this // is still OK to do. void say_four() { printf("4"); } // Forward-declared prototypes that are defined in one of our other C files. void say_two(); // main1.c void say_three(); // main2.c #endif /* HEADER */ c2go-0.26.10/tests/multi/main1.c000066400000000000000000000006621410601753200161620ustar00rootroot00000000000000#include #include "header.h" #define ERROR_FUNC error #include "err.h" #undef ERROR_FUNC #define ERROR_FUNC errorANOTHER #include "err.h" int main() { say_two(); say_three(); say_four(); ERROR_FUNC(); error(); errorANOTHER(); return 0; } // The body for the definition (declared in the header). Notice this is declared // after using the forward declaration above. void say_two() { printf("2"); } c2go-0.26.10/tests/multi/main2.c000066400000000000000000000001161410601753200161550ustar00rootroot00000000000000#include #include "header.h" void say_three() { printf("3"); } c2go-0.26.10/tests/operators.c000066400000000000000000000216411410601753200160410ustar00rootroot00000000000000#include #include "tests.h" // TODO: More comprehensive operator tests // https://github.com/elliotchance/c2go/issues/143 void empty(){;} int sAdd(char *opt) { int l = strlen(opt) + 12; return l; } int sMul(char *opt) { int l = strlen(opt) * 12; return l; } int sMin(char *opt) { int l = strlen(opt) - 12; return l; } int sDiv(char *opt) { int l = strlen(opt) / 12; return l; } int simple_repeat(int a) { return a; } double * return_null(){ return NULL; } typedef struct doubleEqual{ int a; unsigned int b; } doubleEqual; typedef unsigned int pcre_uint32; typedef unsigned char pcre_uint8; typedef unsigned char pcre_uchar; #define UCHAR21INCTEST(eptr) (*(eptr)++) #define PCRE_PUCHAR const pcre_uchar * #define PREP_A 0x0002 #define PREP_B 0x0010 void unusedInt(int n) { ; } int main() { plan(142); int i = 10; signed char j = 1; float f = 3.14159f; double d = 0.0; char c = 'A'; i %= 10; is_eq(i, 0); i += 10; is_eq(i, 10); i -= 2; is_eq(i, 8); i *= 2; is_eq(i, 16); i /= 4; is_eq(i, 4); i <<= 2; is_eq(i, 16); i >>= 2; is_eq(i, 4); i ^= 0xCFCF; is_eq(i, 53195); i |= 0xFFFF; is_eq(i, 65535); i &= 0x0000; is_eq(i, 0); diag("Other types"); f += 1.0f; is_eq(f, 4.14159); d += 1.25f; is_eq(d, 1.25); i -= 255l; is_eq(i, -255); i += 'A'; is_eq(i, -190); c += 11; is_eq(c, 76); diag("Shift with signed int"); i = 4 << j; is_eq(i, 8); i = 8 >> j; is_eq(i, 4); i <<= j; is_eq(i, 8); i >>= j; is_eq(i, 4); diag("Operator equal for 1 variables"); int x; x = 42; is_eq(x, 42); diag("Operator equal for 2 variables"); int y; x = y = 1; is_eq(x, 1); is_eq(y, 1); diag("Operator comma in initialization"); int x2 = 0, y2 = 1; is_eq(x2, 0); is_eq(y2, 1); diag("Operator equal for 3 variables"); int a,b,c2; a = b = c2 = 3; is_eq(a, 3); is_eq(b, 3); is_eq(c2, 3); diag("Huge comma problem for Equal operator") int q,w,e; q = 7, w = q + 3, e = q + w; is_eq(q, 7); is_eq(w, 10); is_eq(e, 17); diag("Huge comma problem for Equal operator with Multiplication") float qF,wF,eF; qF = 7., wF = qF * 3., eF = qF * wF; float expectedQ = 7.; float expectedW = 7. * 3.; float expectedE = 7. * (7. * 3.); is_eq(qF, expectedQ); is_eq(wF, expectedW); is_eq(eF, expectedE); diag("Statement expressions") int s1 = ({ 2; }); is_eq(s1, 2); is_eq(({ int foo = s1 * 3; foo + 1; }), 7); diag("Not allowable var name for Go") int type = 42; is_eq(type,42); diag("Go keywords inside C code") { int chan = 42; is_eq(chan ,42); } { int defer = 42; is_eq(defer ,42); } { int fallthrough = 42; is_eq(fallthrough ,42); } { int func = 42; is_eq(func ,42); } { int go = 42; is_eq(go ,42); } { int import = 42; is_eq(import ,42); } { int interface = 42; is_eq(interface ,42); } { int map = 42; is_eq(map ,42); } { int package = 42; is_eq(package ,42); } { int range = 42; is_eq(range ,42); } { int select = 42; is_eq(select ,42); } { int type = 42; is_eq(type ,42); } { int var = 42; is_eq(var ,42); } { int _ = 42; is_eq(_ ,42); } // checking is_eq is no need, because if "(void)(az)" not transpile, // then go build return fail - value is not used diag("CStyleCast "); { char **az; (void)(az); } { double *const*az; (void)(az); } { int **az; (void)(az); } { float *volatile*az; (void)(az); } diag("CStyleCast with comma"); { unsigned int *ui; (void)(empty(),ui);} { long int *li; int counter_li = 0; (void)(counter_li++,empty(),li); is_eq(counter_li,1); } diag("switch with initialization"); switch(0) { int ii; case 0: { ii = 42; is_eq(ii,42); } case 1: { ii = 50; is_eq(ii,50); } } switch(1) { int ia; case 0: { ia = 42; is_eq(ia,42); } case 1: { ia = 60; is_eq(ia,60); } } diag("Binary operators for definition function"); is_eq(sAdd("rrr"),15); is_eq(sMul("rrr"),36); is_eq(sMin("rrrrrrrrrrrrr"),1); is_eq(sDiv("rrrrrrrrrrrr"),1); diag("Operators +=, -=, *= , /= ... inside []"); { int a[3]; a[0] = 5; a[1] = 9; a[2] = -13; int iterator = 0; is_eq(a[iterator++], 5); is_eq(a[iterator] , 9); is_eq(a[++iterator],-13); is_eq(a[iterator-=2], 5); is_eq(a[iterator+=1], 9); is_eq(a[(iterator = 0,iterator )] , 5); is_eq(simple_repeat((iterator = 42, iterator)),42); is_eq(simple_repeat((iterator = 42, ++iterator, iterator)),43); int b = 0; for ( iterator = 0; b++, iterator < 2; iterator ++, iterator --, iterator ++) { pass("iterator in for"); } is_eq(b,3); iterator = 0; if (i++ > 0) { pass("i++ > 0 is pass"); } } diag("Equals a=b=c=..."); { int a,b,c,d; a=b=c=d=42; is_eq(a,42); is_eq(d,42); } { double a,b,c,d; a=b=c=d=42; is_eq(a,42); is_eq(d,42); } { int a,b,c,d = a = b = c = 42; is_eq(a,42); is_eq(d,42); } { double a,b,c,d = a = b = c = 42; is_eq(a,42); is_eq(d,42); } { double a[3]; a[0] = a[1] = a[2] = -13; is_eq(a[0],-13); is_eq(a[2],-13); } { double a[3]; a[0] = a[1] = a[2] = -13; double b[3]; b[0] = b[1] = b[2] = 5; b[0] = a[0] = 42; is_eq(a[0], 42); is_eq(b[0], 42); } { double v1 = 12; int v2 = -6; double *b = &v1; int *a = &v2; *b = *a = 42; is_eq(*a, 42); is_eq(*b, 42); } { doubleEqual de; de.a = de.b = 42; is_eq(de.a, 42); is_eq(de.b, 42); doubleEqual *dep = &de; dep->a = dep->b = 9; is_eq(dep->a, 9); is_eq(dep->b, 9); de.a += de.b -= 2; is_eq(de.a, 16); is_eq(de.b, 7); int n,m,p; n = m = p = 0; for(de.a = de.b = 0; de.a < 2; de.b = de.a++) { is_eq(n, de.a); n = m = ++p ; is_eq(n-1, de.a); } is_eq(de.a, 2); is_eq(de.b, 1); is_eq(n, 2); is_eq(m, 2); switch(de.a = de.b = 42) { case 42: pass("switch equals a=b="); break; default: fail("code should not reach here"); } } { int yy = 0; unusedInt(yy); if ((yy = simple_repeat(42)) > 3) { pass("ok") } } diag("pointer in IF"); double *cd; if ( (cd = return_null()) == NULL ){ pass("ok"); } (void)(cd); diag("increment for char"); { char N = 'g'; int aaa = 0; if ( (aaa++,N--,aaa+=3,N) == 102) { pass("ok"); } (void)(aaa); } diag("Comma with operations"); { int x,y,z; x = y = z = 1; x <<= y <<= z <<= 1; is_eq(x, 16); is_eq(y, 4); is_eq(z, 2); } { int x,y,z; x = y = z = 1000; x /= y /= z /= 2; is_eq(x, 500); is_eq(y, 2); is_eq(z, 500); } { int x,y,z; x = y = z = 3; x *= y *= z *= 2; is_eq(x, 54); is_eq(y, 18); is_eq(z, 6 ); } { int x, y = 2; ((x = 3),(y -= 1)); is_eq(x, 3); is_eq(y, 1); } diag("Bitwise complement of array"); { int a[] = { 0x3c, 0xff }; a[1] &= ~a[0]; is_eq(a[1], 0xc3); pcre_uint8 b[] = { 0xff }; b[0] &= ~0x3c; is_eq(b[0], 0xc3); } diag("Pointer increment/decrement"); { pcre_uchar s[] = "abcd"; pcre_uchar *a = &s[1]; pcre_uchar *b = a++; is_true(a == &s[2]); is_true(b == &s[1]); b = ++a; is_true(a == &s[3]); is_true(b == &s[3]); b = a--; is_true(a == &s[2]); is_true(b == &s[3]); b = --a; is_true(a == &s[1]); is_true(b == &s[1]); } diag("Value increment/decrement"); { pcre_uint8 a = 4; pcre_uint8 b = a++; is_eq(a, 5); is_eq(b, 4); b = ++a; is_eq(a, 6); is_eq(b, 6); b = a--; is_eq(a, 5); is_eq(b, 6); b = --a; is_eq(a, 4); is_eq(b, 4); } diag("Take address of complex expression"); { pcre_uchar s[] = "abcd"; pcre_uchar *a = &s[1]; pcre_uchar *b = &s[0]; is_eq(a + 2 - 1 - b, 2); is_true(a + 2 - 1 == b + 2) pcre_uchar *c; c = &(*(&s[1] + 1)); is_true(c == a+1); } diag("Increment with parenthesis"); { const pcre_uchar str[] = "abcdef"; PCRE_PUCHAR p = str; pcre_uint32 pp = UCHAR21INCTEST(p); pcre_uint32 pp2 = *p; is_eq(pp, 'a'); is_eq(pp2, 'b'); } diag("Increment with assign"); { pcre_uchar str[] = "abcdef"; pcre_uchar *p = str; pcre_uint32 pp; pcre_uint32 pp2 = *p; PCRE_PUCHAR p2 = p; pp = *p++ = 'z'; pp2 = *p; is_eq(*p2, 'z'); is_eq(pp, 'z'); is_eq(pp2, 'b'); } diag("Test complement"); { unsigned long int flags = 32; flags &= ~(PREP_A|PREP_B); is_eq(flags, 32); } diag("Increment pointer in struct"); { struct aStruct { char *a; } v; v.a = "Hello"; ++v.a; is_streq(v.a, "ello"); } diag("Increment pointer via poiter"); { char *s = "World"; char **p = &s; ++*p; is_streq(s, "orld"); } done_testing(); } c2go-0.26.10/tests/scanf.c000066400000000000000000000003261410601753200151120ustar00rootroot00000000000000// scanf() needs to be in it's own file because it takes input from stdin. #include #include "tests.h" int main() { plan(1); int i; scanf("%d", &i); is_eq(i, 7); done_testing(); } c2go-0.26.10/tests/sizeof.c000066400000000000000000000045771410601753200153330ustar00rootroot00000000000000// This file contains tests for the sizeof() function and operator. #include #include "tests.h" #define check_sizes(type, size) \ is_eq(sizeof(type), size); \ is_eq(sizeof(unsigned type), size); \ is_eq(sizeof(signed type), size); \ is_eq(sizeof(const type), size); \ is_eq(sizeof(volatile type), size); #define FLOAT(type, size) \ is_eq(sizeof(type), size); #define OTHER(type, size) \ is_eq(sizeof(type), size); // We print the variable so that the compiler doesn't complain that the variable // is unused. #define VARIABLE(v, p) \ printf("%s = (%d) %d bytes\n", #v, p, sizeof(v)); struct MyStruct { double a; char b; char c; }; struct MyStruct2 { double a; char b; char c; char d[10]; }; struct MyStruct3 { double a; char b; char c; char d[20]; }; struct MyStruct4 { double a; char b; char c; char d[30]; }; union MyUnion { double a; char b; int c; }; short a; int b; int main() { plan(42); diag("Integer types"); check_sizes(char, 1); check_sizes(short, 2); check_sizes(int, 4); check_sizes(long, 8); diag("Floating-point types"); is_eq(sizeof(float), 4); is_eq(sizeof(double), 8); is_eq(sizeof(long double), 16); diag("Other types"); is_eq(sizeof(void), 1); diag("Pointers"); is_eq(sizeof(char *), 8); is_eq(sizeof(char *), 8); is_eq(sizeof(short **), 8); diag("Variables"); a = 123; b = 456; struct MyStruct s1; s1.b = 0; struct MyStruct2 s2; s2.b = 0; struct MyStruct3 s3; s3.b = 0; struct MyStruct4 s4; s4.b = 0; union MyUnion u1; u1.b = 0; is_eq(sizeof(a), 2); is_eq(sizeof(b), 4); is_eq(sizeof(s1), 16); is_eq(sizeof(s2), 24); is_eq(sizeof(s3), 32); is_eq(sizeof(s4), 40); is_eq(sizeof(u1), 8); diag("Structures"); is_eq(sizeof(struct MyStruct), 16); diag("Unions"); is_eq(sizeof(union MyUnion), 8); diag("Function pointers"); is_eq(sizeof(main), 1); diag("Arrays"); char c[3] = {'a', 'b', 'c'}; c[0] = 'a'; is_eq(sizeof(c), 3); int *d[3]; d[0] = &b; is_eq(sizeof(d), 24); int **e[4]; e[0] = d; is_eq(sizeof(e), 32); const char * const f[] = {"a", "b", "c", "d", "e", "f"}; is_eq(sizeof(f), 48); is_streq(f[1], "b"); done_testing(); } c2go-0.26.10/tests/stdarg.c000066400000000000000000000047161410601753200153130ustar00rootroot00000000000000#include #include #include #include "tests.h" #define START_TEST(t) \ diag(#t); \ test_##t(); void simple(const char* fmt, ...) { char buffer[155]; for (int i=0;i<155;i++){ buffer[i] = 0; } is_streq(buffer, ""); va_list args; va_start(args, fmt); char temp[100]; for (int i=0;i<100;i++){ temp[i] = 0; } int len = 4; for (int i=0;i #include #include "tests.h" _Bool f(_Bool b){ return b; } int main() { plan(12); bool trueBool = true; bool falseBool = false; is_true(trueBool); is_false(falseBool); if (trueBool) { pass("%s", "true") } else { fail("%s", "should not reach here") } if (!trueBool) { fail("%s", "should not reach here") } else { pass("%s", "true") } if (falseBool) { fail("%s", "should not reach here") } else { pass("%s", "false") } if (!falseBool) { pass("%s", "false") } else { fail("%s", "should not reach here") } _Bool var = true; if(var) { pass("%s", "ok") } else { fail("%s", "should not reach here") } var = true; if(var-var) { fail("%s", "should not reach here") } else { pass("%s", "ok") } var = true; if(var - var == false) { pass("%s", "ok") } else { fail("%s", "should not reach here") } _Bool b = 0; // false if (b){ b++;} if (b == false) // b = 0 { pass("%s", "ok") } _Bool c = f(b); b = b + c; if (b == false) { pass("%s", "ok") } int i = (int)(b); if (i == 0) { pass("%s", "ok") } done_testing(); } c2go-0.26.10/tests/stdio.c000066400000000000000000000310241410601753200151410ustar00rootroot00000000000000// This program actually still works without including stdio.h but it should be // here for consistency. #include #include #include #include #include #include "tests.h" #define START_TEST(t) \ diag(#t); \ test_##t(); // size of that file int filesize = 12820; void test_putchar() { putchar('#'); char c; for (c = 'A'; c <= 'Z'; c++) putchar(c); putchar('\n'); pass("%s", "putchar"); } void test_puts() { puts("#c2go"); pass("%s", "puts"); } void test_printf() { // TODO: printf() has a different syntax to Go // https://github.com/elliotchance/c2go/issues/94 printf("# Characters: %c %c \n", 'a', 65); //printf("Decimals: %d %ld\n", 1977, 650000L); printf("# Preceding with blanks: %10d \n", 1977); printf("# Preceding with zeros: %010d \n", 1977); printf("# Some different radices: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100); printf("# floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416); printf("# Width trick: %*d \n", 5, 10); printf("# %s \n", "A string"); int magnitude = 4; char printfFormat[30] = "%0"; char magnitudeString[10]; sprintf(magnitudeString, "%d", magnitude); strcat(printfFormat, magnitudeString); strcat(printfFormat, "d "); printf("# "); printf(printfFormat, 120); printf(" \n"); pass("%s", "printf"); } void test_remove() { // TODO: This does not actually test successfully deleting a file. if (remove("myfile.txt") != 0) { pass("%s", "error deleting file"); } else { fail("%s", "file successfully deleted"); } } void test_rename() { // TODO: This does not actually test successfully renaming a file. int result; char oldname[] = "oldname.txt"; char newname[] = "newname.txt"; result = rename(oldname, newname); if (result == 0) { fail("%s", "File successfully renamed"); } else { pass("%s", "Error renaming file"); } } void test_fopen() { FILE *pFile; pFile = fopen("/tmp/myfile.txt", "w"); if (pFile != NULL) { is_not_null(pFile); fclose(pFile); } } void test_tmpfile() { char buffer[256]; FILE *pFile; pFile = tmpfile(); fputs("hello world", pFile); rewind(pFile); fputs(fgets(buffer, 256, pFile), stdout); fclose(pFile); } void test_strerror() { FILE *pFile; pFile = fopen("/tmp/nonexistantfile.dfjisz985bed9ztszosvep98zwibvezgrxdizbseiu.txt", "r"); is_true(pFile == NULL); is_eq(errno, ENOENT); char *error = strerror(errno); is_streq(error, "No such file or directory"); errno = 0; is_eq(errno, 0); } void test_tmpnam() { // TODO: This is a tricky one to test because the output of tmpnam() in C // and Go will be different. I will keep the test here so at least it tries // to run the code but the test itself is not actually proving anything. char *pointer; // FIXME: We cannot pass variables by reference yet, which is a legitimate // way to use tmpnam(). I have to leave this disabled for now. // // char buffer[L_tmpnam]; // tmpnam(buffer); // assert(buffer != NULL); pointer = tmpnam(NULL); is_not_null(pointer); } void test_fclose() { remove("/tmp/myfile.txt"); FILE *pFile; pFile = fopen("/tmp/myfile.txt", "w"); fputs("fclose example", pFile); fclose(pFile); // remove temp file is_eq(remove("/tmp/myfile.txt"),0) } void test_fflush() { char mybuffer[80]; FILE *pFile; pFile = fopen("/tmp/example.txt", "w+"); is_not_null(pFile) or_return(); fputs("test", pFile); fflush(pFile); // flushing or repositioning required fgets(mybuffer, 80, pFile); fclose(pFile); // check correct value written to file pFile = fopen("/tmp/example.txt", "r"); is_not_null(pFile) or_return(); fgets(mybuffer, 80, pFile); is_streq(mybuffer, "test"); fclose(pFile); // check that fopen with w flag truncates the file pFile = fopen("/tmp/example.txt", "w"); is_not_null(pFile) or_return(); fputs(".", pFile); fclose(pFile); pFile = fopen("/tmp/example.txt", "r"); is_not_null(pFile) or_return(); fgets(mybuffer, 80, pFile); is_streq(mybuffer, "."); fclose(pFile); // remove temp file is_eq(remove("/tmp/example.txt"),0) } void test_fprintf() { remove("/tmp/myfile1.txt"); FILE *pFile; int n; char *name = "John Smith"; pFile = fopen("/tmp/myfile1.txt", "w"); is_not_null(pFile); for (n = 0; n < 3; n++) { fprintf(pFile, "Name %d [%-10.10s]\n", n + 1, name); } fclose(pFile); // remove temp file is_eq(remove("/tmp/myfile1.txt"),0) } void test_fscanf() { remove("/tmp/myfile2.txt"); char str[80]; char end[80]; float f; int i; FILE *pFile; pFile = fopen("/tmp/myfile2.txt", "w+"); is_not_null(pFile); fprintf(pFile, "%f \r\n %s %d %s", 3.1416, "PI", 42, "end"); rewind(pFile); fscanf(pFile, "%f", &f); fscanf(pFile, "%s", str); fscanf(pFile, "%d", &i); fscanf(pFile, "%s", end); fclose(pFile); pFile = NULL; is_eq(f, 3.1416); is_streq(str, "PI"); is_eq(i,42); is_streq(end,"end"); // read again FILE *pFile2; pFile2 = fopen("/tmp/myfile2.txt", "r"); is_not_null(pFile2); fscanf(pFile2, "%f", &f); fscanf(pFile2, "%s", str); fscanf(pFile2, "%d", &i); fscanf(pFile2, "%s", end); fclose(pFile2); pFile2 = NULL; is_eq(f, 3.1416); is_streq(str, "PI"); is_eq(i,42); is_streq(end,"end"); // remove temp file is_eq(remove("/tmp/myfile2.txt"),0) } void test_fgetc() { FILE *pFile; int c; int n = 0; pFile = fopen("tests/stdio.c", "r"); is_not_null(pFile); do { c = fgetc(pFile); if (c == '$') n++; } while (c != EOF); fclose(pFile); is_eq(n, 2); } void test_fgets() { FILE *pFile; char *mystring; char dummy[20]; pFile = fopen("tests/stdio.c", "r"); is_not_null(pFile); mystring = fgets(dummy, 20, pFile); is_not_null(mystring); fclose(pFile); } void test_fgets2() { FILE *pFile; char *mystring; char buffer[5]; pFile = fopen("/tmp/mylog.txt", "w"); fputs("asdfgh\nijk\n", pFile); fclose(pFile); pFile = fopen("/tmp/mylog.txt", "r"); is_not_null(pFile); mystring = fgets(buffer, 5, pFile); is_not_null(mystring); is_streq(buffer, "asdf"); is_streq(mystring, "asdf"); is_true(buffer == mystring); is_eq(strlen(buffer), 4) mystring = fgets(buffer, 5, pFile); is_streq(buffer, "gh\n"); is_streq(mystring, "gh\n"); is_eq(strlen(buffer), 3) mystring = fgets(buffer, 5, pFile); is_streq(buffer, "ijk\n"); is_streq(mystring, "ijk\n"); is_eq(strlen(buffer), 4); is_eq(buffer[4], 0); is_false(feof(pFile)); is_false(ferror(pFile)); mystring = fgets(buffer, 5, pFile); is_streq(buffer, "ijk\n"); is_true(NULL == mystring); is_true(feof(pFile)); is_false(ferror(pFile)); fclose(pFile); // remove temp file is_eq(remove("/tmp/mylog.txt"),0) } void test_fputc() { char c; fputc('#', stdout); for (c = 'A'; c <= 'Z'; c++) fputc(c, stdout); fputc('\n', stdout); } void test_fputs() { FILE *pFile; char *sentence = "Hello, World"; pFile = fopen("/tmp/mylog.txt", "w"); fputs(sentence, pFile); fclose(pFile); // remove temp file is_eq(remove("/tmp/mylog.txt"),0) } void test_getc() { FILE *pFile; int c; int n = 0; pFile = fopen("tests/stdio.c", "r"); is_not_null(pFile); do { c = getc(pFile); if (c == '$') n++; } while (c != EOF); fclose(pFile); is_eq(n, 2); } void test_putc() { FILE *pFile; char c; pFile = fopen("/tmp/whatever.txt", "w"); for (c = 'A'; c <= 'Z'; c++) { putc(c, pFile); } fclose(pFile); // remove temp file is_eq(remove("/tmp/whatever.txt"),0) } void test_fseek() { FILE *pFile; pFile = fopen("/tmp/example.txt", "w"); fputs("This is an apple.", pFile); fseek(pFile, 9, SEEK_SET); fputs(" sam", pFile); fclose(pFile); // remove temp file is_eq(remove("/tmp/example.txt"),0) } void test_ftell() { FILE *pFile; long size; pFile = fopen("tests/stdio.c", "r"); is_not_null(pFile); fseek(pFile, 0, SEEK_END); // non-portable size = ftell(pFile); fclose(pFile); is_eq(size, filesize); } void test_fread() { FILE *pFile; int lSize; char buffer[1024]; int result; pFile = fopen("tests/getchar.c", "r"); is_not_null(pFile); // obtain file size: fseek(pFile, 0, SEEK_END); lSize = ftell(pFile); is_eq(lSize, 216); rewind(pFile); // copy the file into the buffer: result = fread(buffer, 1, lSize, pFile); is_eq(result, lSize); // See issue #107 buffer[lSize - 1] = 0; is_eq(strlen(buffer), 215); // terminate fclose(pFile); } void test_fwrite() { FILE *pFile; pFile = fopen("/tmp/myfile.bin", "w"); fwrite("xyz", 1, 3, pFile); fclose(pFile); // remove temp file is_eq(remove("/tmp/myfile.bin"),0) } void test_fgetpos() { FILE *pFile; int c; int n; fpos_t pos; pFile = fopen("tests/stdio.c", "r"); is_not_null(pFile); c = fgetc(pFile); is_eq(c, '/'); fgetpos(pFile, &pos); for (n = 0; n < 3; n++) { fsetpos(pFile, &pos); c = fgetc(pFile); is_eq(c, '/'); } fclose(pFile); } void test_fsetpos() { FILE *pFile; fpos_t position; pFile = fopen("/tmp/myfile.txt", "w"); fgetpos(pFile, &position); fputs("That is a sample", pFile); fsetpos(pFile, &position); fputs("This", pFile); fclose(pFile); // remove temp file is_eq(remove("/tmp/myfile.txt"),0) } void test_rewind() { int n; FILE *pFile; char buffer[27]; pFile = fopen("/tmp/myfile.txt", "w+"); for (n = 'A'; n <= 'Z'; n++) fputc(n, pFile); rewind(pFile); fread(buffer, 1, 26, pFile); fclose(pFile); buffer[26] = '\0'; is_eq(strlen(buffer), 26); // remove temp file is_eq(remove("/tmp/myfile.txt"),0) } void test_feof() { FILE *pFile; int n = 0; pFile = fopen("tests/stdio.c", "r"); is_not_null(pFile); while (fgetc(pFile) != EOF) { ++n; } if (feof(pFile)) { pass("%s", "End-of-File reached."); is_eq(n, filesize); } else { fail("%s", "End-of-File was not reached."); } fclose(pFile); } void test_sprintf() { char buffer [100]; int cx; cx = snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 ); is_streq(buffer,"The half of 60 is 30"); is_eq(cx,20); } void test_snprintf() { char buffer [50]; int n, a=5, b=3; n = sprintf (buffer, "%d plus %d is %d", a, b, a+b); is_streq(buffer, "5 plus 3 is 8") is_eq(n,13) } int PrintFError(const char * format, ... ) { char buffer[256]; va_list args; va_start (args, format); int s = vsprintf (buffer,format, args); va_end (args); return s; } void test_vsprintf() { int s = PrintFError("Success function '%s' %.2f","vsprintf",3.1415926); is_eq(s,19+8+5); } int PrintFError2(const char * format, ... ) { char buffer[256]; va_list args; va_start (args, format); int s = vsnprintf (buffer,256,format, args); va_end (args); return s; } void test_vsnprintf() { int s = PrintFError2("Success function '%s' %.2f","vsprintf",3.1415926); is_eq(s,19+8+5); } void test_eof() { if ( (int)(EOF) == -1 ) { pass("ok"); } char c = EOF; if ( c == (char)(EOF) ) { pass("ok"); } char a[1]; a[0] = 's'; if ( a[0] != EOF ) { pass("ok"); } a[0] = EOF; if ( a[0] != EOF ) { fail("EOF == EOF - fail"); } else { pass("ok"); } } int main() { plan(90); START_TEST(putchar) START_TEST(puts) START_TEST(printf) START_TEST(remove) START_TEST(rename) START_TEST(fopen) START_TEST(tmpfile) START_TEST(tmpnam) START_TEST(fclose) START_TEST(fflush) START_TEST(printf) START_TEST(fprintf) START_TEST(fscanf) START_TEST(fgetc) START_TEST(fgets) START_TEST(fgets2) START_TEST(fputc) START_TEST(fputs) START_TEST(getc) START_TEST(putc) START_TEST(fseek) START_TEST(ftell) START_TEST(fread) START_TEST(fwrite) START_TEST(fgetpos) START_TEST(fsetpos) START_TEST(rewind) START_TEST(feof) START_TEST(sprintf) START_TEST(snprintf) START_TEST(vsprintf) START_TEST(vsnprintf) START_TEST(eof) START_TEST(strerror) done_testing(); } c2go-0.26.10/tests/stdlib.c000066400000000000000000000304451410601753200153060ustar00rootroot00000000000000#include #include #include #include "tests.h" #define test_strto0(actual, func, end) \ /* strtod */ \ func(strtod(actual, &endptr)); \ func(strtod(actual, NULL)); \ is_streq(endptr, end); \ /* strtof */ \ func(strtof(actual, &endptr)); \ func(strtof(actual, NULL)); \ is_streq(endptr, end); \ /* strtold */ \ func(strtold(actual, &endptr)); \ func(strtold(actual, NULL)); \ is_streq(endptr, end); #define test_strto1(actual, func, expected, end) \ /* strtod */ \ func(strtod(actual, &endptr), expected); \ func(strtod(actual, NULL), expected); \ is_streq(endptr, end); \ /* strtof */ \ func(strtof(actual, &endptr), expected); \ func(strtof(actual, NULL), expected); \ is_streq(endptr, end); \ /* strtold */ \ func(strtold(actual, &endptr), expected); \ func(strtold(actual, NULL), expected); \ is_streq(endptr, end); #define test_ato(actual, expected, end) \ /* atoi */ \ is_eq(atoi(actual), expected); \ /* atol */ \ is_eq(atol(actual), expected); \ /* atoll */ \ is_eq(atoll(actual), expected); \ /* strtol */ \ is_eq(strtol(actual, &endptr, 10), expected); \ is_streq(endptr, end); \ is_eq(strtol(actual, NULL, 10), expected); \ /* strtoll */ \ is_eq(strtoll(actual, &endptr, 10), expected); \ is_streq(endptr, end); \ is_eq(strtoll(actual, NULL, 10), expected); \ /* strtoul */ \ if (expected >= 0) { \ is_eq(strtoul(actual, &endptr, 10), expected); \ is_streq(endptr, end); \ is_eq(strtoul(actual, NULL, 10), expected); \ } \ /* strtoull */ \ if (expected >= 0) { \ is_eq(strtoull(actual, &endptr, 10), expected); \ is_streq(endptr, end); \ is_eq(strtoull(actual, NULL, 10), expected); \ } #define test_strtol(actual, radix, expected, end) \ /* strtol */ \ is_eq(strtol(actual, &endptr, radix), expected); \ is_streq(endptr, end); \ /* strtoll */ \ is_eq(strtoll(actual, &endptr, radix), expected); \ is_streq(endptr, end); \ /* strtoul */ \ is_eq(strtoul(actual, &endptr, radix), expected); \ is_streq(endptr, end); \ /* strtoull */ \ is_eq(strtoull(actual, &endptr, radix), expected); \ is_streq(endptr, end); void test_malloc1() { diag("malloc1"); int i = 16, n; char *buffer; buffer = (char *)malloc(i + 1); is_not_null(buffer) or_return(); for (n = 0; n < i; n++) buffer[n] = i % 26 + 'a'; buffer[i] = '\0'; is_streq(buffer, "qqqqqqqqqqqqqqqq"); free(buffer); } void test_malloc2() { diag("malloc2"); int *p; p = (int *)malloc(sizeof(int)); is_not_null(p) or_return(); *p = 5; is_eq(*p, 5); } // Mix around all the types to make sure it is still actually allocating the // correct size. void test_malloc3() { diag("malloc3"); is_eq(sizeof(int), 4); is_eq(sizeof(double), 8); // 10 ints, should be 5 doubles. Also use a bad cast to make sure that it // doesn't interfere with the types. double *d; d = (char *)malloc(sizeof(int) * 10); is_not_null(d) or_return(); // We can't test how much memory has been allocated by Go, but we can test // that there are 5 items. *d = 123; d[4] = 456; is_eq(*d, 123); is_eq(d[4], 456); } void test_malloc4() { diag("malloc4"); int length = 5; char *m = malloc(length * sizeof(char)); is_not_null(m) or_return(); (void)(m); char *m2 = malloc(sizeof(char) * length); is_not_null(m2) or_return(); (void)(m2); char *m3; m3 = malloc(sizeof(char) * length); is_not_null(m3) or_return(); (void)(m3); char *m4; m4 = malloc(length * sizeof(char)); is_not_null(m4) or_return(); (void)(m4); } void test_malloc5() { diag("malloc5"); size_t size = 16; void *block = malloc(size); unsigned char *buffer = (unsigned char*) block; is_not_null(buffer) or_return(); for (int n = 0; n < size-1; n++) buffer[n] = size % 26 + 'a'; buffer[size-1] = '\0'; is_streq((const char*)buffer, "qqqqqqqqqqqqqqq"); free(block); } // calloc() works exactly the same as malloc() however the memory is zeroed out. // In Go all allocated memory is zeroed out so they actually are the same thing. void test_calloc() { diag("calloc"); is_eq(sizeof(int), 4); is_eq(sizeof(double), 8); // 10 ints, should be 5 doubles. Also use a bad cast to make sure that it // doesn't interfere with the types. double *d; d = (char *)calloc(10,sizeof(int)); is_not_null(d) or_return(); // We can't test how much memory has been allocated by Go, but we can test // that there are 5 items. *d = 123; d[4] = 456; is_eq(*d, 123); is_eq(d[4], 456); } void test_free() { int * buffer1, * buffer2, * buffer3; buffer1 = (int*) malloc (100*sizeof(int)); buffer2 = (int*) calloc (100,sizeof(int)); buffer3 = (int*) realloc (buffer2,500*sizeof(int)); int i = 0; free ((i += 1, buffer1)); if (buffer2 != NULL){ i+=1; } if (i == 2) { free (buffer3); i++; } is_eq(i,3); } int values[] = { 40, 10, 100, 90, 20, 25 }; int compare (const void * a, const void * b) { return ( *(int*)a - *(int*)b ); } void q_sort(){ diag("qsort") qsort (values, 6, sizeof(int), compare); is_eq(values[0], 10 ); is_eq(values[1], 20 ); is_eq(values[2], 25 ); is_eq(values[3], 40 ); is_eq(values[4], 90 ); is_eq(values[5], 100 ); } int main() { plan(754); char *endptr; diag("abs") is_eq(abs(-5), 5); is_eq(abs(7), 7); is_eq(abs(0), 0); diag("atof") is_eq(atof("123"), 123); is_eq(atof("1.23"), 1.23); is_eq(atof(""), 0); is_eq(atof("1.2e6"), 1.2e6); is_eq(atof(" \n123"), 123); is_eq(atof("\t123foo"), 123); is_eq(atof("+1.23"), 1.23); is_eq(atof("-1.23"), -1.23); is_eq(atof("1.2E-6"), 1.2e-6); is_eq(atof("1a2b"), 1); is_eq(atof("1a.2b"), 1); is_eq(atof("a1.2b"), 0); is_eq(atof("1.2Ee-6"), 1.2); is_eq(atof("-1..23"), -1); is_eq(atof("-1.2.3"), -1.2); is_eq(atof("foo"), 0); is_eq(atof("+1.2+3"), 1.2); is_eq(atof("-1.-23"), -1); is_eq(atof("-.23"), -0.23); is_eq(atof(".4"), 0.4); is_eq(atof("0xabc"), 2748); is_eq(atof("0x1b9"), 441); is_eq(atof("0x"), 0); is_eq(atof("0X1f9"), 505); is_eq(atof("-0X1f9"), -505); is_eq(atof("+0x1f9"), 505); is_eq(atof("0X"), 0); is_eq(atof("0xfaz"), 250); is_eq(atof("0Xzaf"), 0); is_eq(atof("0xabcp2"), 10992); is_eq(atof("0xabcP3"), 21984); is_eq(atof("0xabcP2z"), 10992); is_eq(atof("0xabcp-2"), 687); is_eq(atof("0xabcp+2"), 10992); is_inf(atof("inf"), 1); is_inf(atof("INF"), 1); is_inf(atof("Inf"), 1); is_inf(atof("-Inf"), -1); is_inf(atof("+INF"), 1); is_inf(atof("infinity"), 1); is_inf(atof("INFINITY"), 1); is_inf(atof("Infinity"), 1); is_inf(atof("+INFINITY"), 1); is_inf(atof("-InfINITY"), -1); is_nan(atof("nan")); is_nan(atof("NaN")); is_nan(atof("+NaN")); is_nan(atof("NAN")); is_nan(atof("-NAN")); is_nan(atof("nanabc123")); is_nan(atof("NANz123")); is_nan(atof("NaN123z")); is_nan(atof("-NANz123")); // This causes a segfault in C: // is_eq(atof(NULL), 0); diag("atoi / atol / atoll / strtol / strtoll / strtoul") test_ato("123", 123, ""); test_ato("+456", 456, ""); test_ato("-52", -52, ""); test_ato("foo", 0, "foo"); test_ato(" \t123", 123, ""); test_ato("", 0, ""); test_ato(" \t", 0, " \t"); test_ato("123abc", 123, "abc"); diag("div") { div_t result = div(17, 5); is_eq(result.quot, 3) is_eq(result.rem, 2) result = div(-17, 5); is_eq(result.quot, -3) is_eq(result.rem, -2) result = div(17, -5); is_eq(result.quot, -3) is_eq(result.rem, 2) result = div(-17, -5); is_eq(result.quot, 3) is_eq(result.rem, -2) } diag("calloc") test_calloc(); // exit() is handled in tests/exit.c // free() is handled with the malloc and calloc tests. diag("free"); test_free(); diag("getenv") is_not_null(getenv("PATH")); is_not_null(getenv("HOME")); is_null(getenv("FOOBAR")); diag("labs") is_eq(labs(-5), 5); is_eq(labs(7), 7); is_eq(labs(0), 0); diag("ldiv") { ldiv_t result = ldiv(17, 5); is_eq(result.quot, 3) is_eq(result.rem, 2) result = ldiv(-17, 5); is_eq(result.quot, -3) is_eq(result.rem, -2) result = ldiv(17, -5); is_eq(result.quot, -3) is_eq(result.rem, 2) result = ldiv(-17, -5); is_eq(result.quot, 3) is_eq(result.rem, -2) } diag("llabs") is_eq(llabs(-5), 5); is_eq(llabs(7), 7); is_eq(llabs(0), 0); diag("lldiv") { lldiv_t result = lldiv(17, 5); is_eq(result.quot, 3) is_eq(result.rem, 2) result = lldiv(-17, 5); is_eq(result.quot, -3) is_eq(result.rem, -2) result = lldiv(17, -5); is_eq(result.quot, -3) is_eq(result.rem, 2) result = lldiv(-17, -5); is_eq(result.quot, 3) is_eq(result.rem, -2) } diag("malloc") test_malloc1(); test_malloc2(); test_malloc3(); test_malloc4(); test_malloc5(); diag("rand") int i, nextRand, lastRand = rand(); for (i = 0; i < 10; ++i) { nextRand = rand(); is_not_eq(lastRand, nextRand) } diag("srand") srand(0); lastRand = rand(); for (i = 0; i < 10; ++i) { nextRand = rand(); is_not_eq(lastRand, nextRand) } srand(0); int a1 = rand(); int a2 = rand(); int a3 = rand(); srand(0); int b1 = rand(); int b2 = rand(); int b3 = rand(); is_eq(a1, b1) is_eq(a2, b2) is_eq(a3, b3) diag("strtod / strtof / strtold") test_strto1("123", is_eq, 123, ""); test_strto1("1.23", is_eq, 1.23, ""); test_strto1("", is_eq, 0, ""); test_strto1("1.2e6", is_eq, 1.2e6, ""); test_strto1(" \n123", is_eq, 123, ""); test_strto1("\t123foo", is_eq, 123, "foo"); test_strto1("+1.23", is_eq, 1.23, ""); test_strto1("-1.23", is_eq, -1.23, ""); test_strto1("1.2E-6", is_eq, 1.2e-6, ""); test_strto1("1a2b", is_eq, 1, "a2b"); test_strto1("1a.2b", is_eq, 1, "a.2b"); test_strto1("a1.2b", is_eq, 0, "a1.2b"); test_strto1("1.2Ee-6", is_eq, 1.2, "Ee-6"); test_strto1("-1..23", is_eq, -1, ".23"); test_strto1("-1.2.3", is_eq, -1.2, ".3"); test_strto1("foo", is_eq, 0, "foo"); test_strto1("+1.2+3", is_eq, 1.2, "+3"); test_strto1("-1.-23", is_eq, -1, "-23"); test_strto1("-.23", is_eq, -0.23, ""); test_strto1(".4", is_eq, 0.4, ""); test_strto1("0xabc", is_eq, 2748, ""); test_strto1("0x1b9", is_eq, 441, ""); test_strto1("0x", is_eq, 0, "x"); test_strto1("0X1f9", is_eq, 505, ""); test_strto1("-0X1f9", is_eq, -505, ""); test_strto1("+0x1f9", is_eq, 505, ""); test_strto1("0X", is_eq, 0, "X"); test_strto1("0xfaz", is_eq, 250, "z"); test_strto1("0Xzaf", is_eq, 0, "Xzaf"); test_strto1("0xabcp2", is_eq, 10992, ""); test_strto1("0xabcP3", is_eq, 21984, ""); test_strto1("0xabcP2z", is_eq, 10992, "z"); test_strto1("0xabcp-2", is_eq, 687, ""); test_strto1("0xabcp+2", is_eq, 10992, ""); test_strto1("inf", is_inf, 1, ""); test_strto1("INF", is_inf, 1, ""); test_strto1("Inf", is_inf, 1, ""); test_strto1("-Inf", is_inf, -1, ""); test_strto1("+INF", is_inf, 1, ""); test_strto1("infinity", is_inf, 1, ""); test_strto1("INFINITY", is_inf, 1, ""); test_strto1("Infinity", is_inf, 1, ""); test_strto1("+INFINITY", is_inf, 1, ""); test_strto1("-InfINITY", is_inf, -1, ""); test_strto0("nan", is_nan, ""); test_strto0("NaN", is_nan, ""); test_strto0("+NaN", is_nan, ""); test_strto0("NAN", is_nan, ""); test_strto0("-NAN", is_nan, ""); test_strto0("nanabc123", is_nan, "abc123"); test_strto0("NANz123", is_nan, "z123"); test_strto0("NaN123z", is_nan, "123z"); test_strto0("-NANz123", is_nan, "z123"); // This causes a segfault in C: // test_strtod1(NULL, is_eq, 0, ""); diag("strtol / strtoll / strtoul / strtoull") test_strtol("123", 8, 83, ""); test_strtol("123abc", 16, 1194684, ""); test_strtol("123abc", 8, 83, "abc"); q_sort(); done_testing(); } c2go-0.26.10/tests/string.c000066400000000000000000000172751410601753200153410ustar00rootroot00000000000000#include #include "tests.h" typedef struct mem { int a; int b; } mem; typedef struct mem2 { int a[2]; } mem2; typedef int altint; void setptr(int *arr, int val) { arr[0] = val; } void setarr(int arr[], int val) { arr[0] = val; } int main() { plan(80); diag("TODO: __builtin_object_size") // https://github.com/elliotchance/c2go/issues/359 { diag("strcpy") char *src = "foo bar\0baz"; char dest1[40]; char *dest2; dest2 = strcpy(dest1, src); is_streq(dest1, "foo bar"); is_streq(dest2, "foo bar"); } diag("strncpy") // If the end of the source C string (which is signaled by a null-character) // is found before num characters have been copied, destination is padded // with zeros until a total of num characters have been written to it. { char *src = "foo bar\0baz"; char dest1[40]; char *dest2; dest1[7] = 'a'; dest1[15] = 'b'; dest1[25] = 'c'; dest2 = strncpy(dest1, src, 20); is_eq(dest1[0], 'f'); is_eq(dest1[7], 0); is_eq(dest1[15], 0); is_eq(dest1[25], 'c'); is_eq(dest2[0], 'f'); is_eq(dest2[7], 0); is_eq(dest2[15], 0); is_eq(dest2[25], 'c'); is_streq(dest1, "foo bar"); is_streq(dest2, "foo bar"); } // No null-character is implicitly appended at the end of destination if // source is longer than num. Thus, in this case, destination shall not be // considered a null terminated C string (reading it as such would // overflow). { char *src = "foo bar\0baz"; char dest1[40]; char *dest2; dest1[7] = 'a'; dest1[15] = 'b'; dest1[25] = 'c'; dest2 = strncpy(dest1, src, 5); is_eq(dest1[0], 'f'); is_eq(dest1[7], 'a'); is_eq(dest1[15], 'b'); is_eq(dest1[25], 'c'); is_eq(dest2[0], 'f'); is_eq(dest2[7], 'a'); is_eq(dest2[15], 'b'); is_eq(dest2[25], 'c'); } { diag("strlen") is_eq(strlen(""), 0); is_eq(strlen("a"), 1); is_eq(strlen("foo"), 3); // NULL causes a seg fault. // is_eq(strlen(NULL), 0); is_eq(strlen("fo\0o"), 2); } { diag("strcat") char str[80]; strcpy (str,"these "); strcat (str,"strings "); strcat (str,"are "); strcat (str,"concatenated."); is_streq(str,"these strings are concatenated."); } { diag("strcmp"); { char* a = "ab"; char* b = "ab"; is_true(strcmp(a,b) == 0); } { char* a = "bb"; char* b = "ab"; is_true(strcmp(a,b) > 0); } { char* a = "ab"; char* b = "bb"; is_true(strcmp(a,b) < 0); } } { diag("strncmp"); { char* a = "ab"; char* b = "ab"; is_true(strncmp(a,b,10) == 0); } { char* a = "bb"; char* b = "ab"; is_true(strncmp(a,b,10) > 0); } { char* a = "ab"; char* b = "bb"; is_true(strncmp(a,b,10) < 0); } { char* a = "aba"; char* b = "ab"; is_true(strncmp(a,b,10) > 0); } { char* a = "ab"; char* b = "aba"; is_true(strncmp(a,b,10) < 0); } { char* a = "aba"; char* b = "abc"; is_true(strncmp(a,b,2) == 0); } } { diag("strchr"); char str[] = "This is a sample string"; char * pch; int amount = 0; pch=strchr(str,'s'); while (pch!=NULL) { pch=strchr(pch+1,'s'); amount ++; } is_eq(amount, 4 ); } { diag("memset"); char dest1[40]; char *dest2; char *dest3; dest2 = (char*) memset(dest1, 'a', 4); dest1[4] = '\0'; is_streq(dest1, "aaaa"); is_streq(dest2, "aaaa"); dest3 = (char*) memset(&dest2[1], 'b', 2); is_streq(dest1, "abba"); is_streq(dest2, "abba"); is_streq(dest3, "bba"); } { diag("memcpy"); char *src = "aaaabb"; char dest1[40]; char *dest2; char *dest3; dest2 = (char*) memcpy(dest1, src, 4); dest1[4] = '\0'; is_streq(dest1, "aaaa"); is_streq(dest2, "aaaa"); dest3 = (char*) memcpy(&dest2[1], &src[4], 2); is_streq(dest1, "abba"); is_streq(dest2, "abba"); is_streq(dest3, "bba"); } { diag("memmove"); char *src = "aaaabb"; char dest1[40]; char *dest2; char *dest3; dest2 = (char*) memmove(dest1, src, 4); dest1[4] = '\0'; is_streq(dest1, "aaaa"); is_streq(dest2, "aaaa"); dest3 = (char*) memmove(&dest2[1], &src[4], 2); is_streq(dest1, "abba"); is_streq(dest2, "abba"); is_streq(dest3, "bba"); } { diag("memset & memcpy of struct / array of struct"); int dest3 = 4; int dest4 = 0xf; memcpy(&dest3, &dest4, sizeof(int)); is_eq(dest3, 0xf); memset(&dest4, 0, sizeof(int)); is_eq(dest4, 0); mem dest5 = { .a = 2, .b = 3.0 }; memset(&dest5, 0, sizeof(mem)); is_eq(dest5.a, 0); is_eq(dest5.b, 0.0); mem dest6[] = { { .a = 2, .b = 3.0 }, { .a = 4, .b = 5.0 } }; mem dest7[2]; memcpy(dest7, dest6, sizeof(mem)*2); memset(dest6, 0, sizeof(mem)*2); is_eq(dest6[0].a, 0); is_eq(dest6[0].b, 0.0); is_eq(dest6[1].a, 0); is_eq(dest6[1].b, 0.0); is_eq(dest7[0].a, 2); is_eq(dest7[0].b, 3.0); is_eq(dest7[1].a, 4); is_eq(dest7[1].b, 5.0); memset(&dest7[1], 0, sizeof(mem)); is_eq(dest7[0].a, 2); is_eq(dest7[0].b, 3.0); is_eq(dest7[1].a, 0); is_eq(dest7[1].b, 0.0); mem2 dest8; dest8.a[0] = 42; memset(dest8.a, 0, sizeof(int)*2); is_eq(dest8.a[0], 0); is_eq(dest8.a[1], 0); dest8.a[0] = 42; mem2 dest9; altint *test = (altint *) dest9.a; memcpy(dest9.a, dest8.a, sizeof(int)*2); is_eq(dest9.a[0], 42); is_eq(test[0], 42); setarr(dest9.a, 1); is_eq(dest9.a[0], 1); setptr(dest9.a, 2); is_eq(dest9.a[0], 2); } { diag("memcmp"); { char* a = "ab\0c"; char* b = "ab\0c"; is_true(memcmp(a,b,4) == 0); } { char* a = "ab\0a"; char* b = "ab\0c"; is_true(memcmp(a,b,4) < 0); } { char* a = "ab\0c"; char* b = "ab\0a"; is_true(memcmp(a,b,4) > 0); } { char* a = "ab\0c"; char* b = "ab\0a"; is_true(memcmp(a,b,3) == 0); } } { diag("strstr"); { char* a = "needle in a haystack"; char* b = "haystack"; char* res = strstr(a,b); is_streq(res, "haystack"); } { char* a = "needle in a haystack"; char* b = "wrong"; char* res = strstr(a,b); is_null(res); } } { diag("strcasestr"); { char* a = "needle in a haystack"; char* b = "HayStack"; char* res = strcasestr(a,b); is_streq(res, "haystack"); } { char* a = "needle in a haystack"; char* b = "wrong"; char* res = strcasestr(a,b); is_null(res); } } done_testing(); } c2go-0.26.10/tests/struct.c000066400000000000000000000321631410601753200153500ustar00rootroot00000000000000// Tests for structures. #include #include #include "tests.h" struct programming { float constant; char *pointer; }; void pass_by_ref(struct programming *addr) { char *s = "Show string member."; float v = 1.23+4.56; addr->constant += 4.56; addr->pointer = s; is_eq(addr->constant, v); is_streq(addr->pointer, "Show string member."); } void pass_by_val(struct programming value) { value.constant++; is_eq(value.constant, 2.23); is_streq(value.pointer, "Programming in Software Development."); } /** * text */ typedef struct mainStruct{ double constant; } secondStruct; /* * Text */ typedef struct { double t; } ts_c; // Text typedef struct ff { int v1,v2; } tt1, tt2; // Text1 // Text2 struct outer { int i; struct z { int j; } inner; }; struct xx { int i; /** * Text */ struct yy { int j; struct zz { int k; } deep; } inner; }; /** * Some function */ int summator(int i, float f){ return i+(int)(f); } typedef struct J J; struct J { float f; int (*fu)(J *j, float i); }; int j_function(J *j, float i) { if (j != NULL) { return (int)(i+(*j).f); } return -1; }; void struct_with_rec_fuction() { J j; j.f = 5.0; j.fu = j_function; is_eq(j.fu(&j,4.0),9); is_eq(j_function(NULL, 4.0),-1); } struct FinFinS { double d; int (*f)(int(*)(int)); }; int FinF1(int a) { return a+1; } int FinF2(int (*f)(int)) { int g = 45; return f(g); } void func_in_func_in_struct() { diag("function in function in struct"); struct FinFinS ffs; ffs.f = FinF2; int res = ffs.f(FinF1) ; is_eq(res , 46); }; struct info { struct deep_info{ int a, b, c; } con; struct star_deep_info{ int sa, sb, sc; } * star_con; }; void struct_in_struct_with_star() { diag("struct in struct with star"); struct info in; in.con.a = 45; is_eq(in.con.a,45); struct star_deep_info st; in.star_con = &st; in.star_con->sa = 45; is_eq(in.star_con->sa,45); struct info in2; struct star_deep_info st2; in2.star_con = &st2; in2.star_con->sa = 46; is_eq(in2.star_con->sa,46); is_eq(in.star_con->sa,45); } struct { int a; } m; typedef double ** y; struct { int aa; } mm; typedef double ** yy; struct mmm{ int aaa; }; typedef double *** yyy; struct mmmm{ int aaaa; }; typedef double **** yyyy; struct mmmmm0{ int aaaaa; }mmmmm; typedef double ** yyyyy; typedef struct { int st1; } st2; typedef double ** st3; typedef struct st4{ int st5; } st6; typedef double ** st7; struct st4 st7a; typedef struct st4a{ int st5a; } * st6a; typedef struct st4b{ int st5b; } *const* st6b; struct st8{ int st9; struct st10{ int st11; }; }; typedef double ** st12; struct st13{ int st14; struct st16{ int st17; }st18; }st19; typedef double ** st20; typedef struct st21{ int st22; struct st23{ int st24; }st25; }st26; typedef double ** st27; static struct unix_syscall { const char *zName; } aSyscall[] = { { "open" }, { "close" } }; struct memory{ int * one; float ** oop; double * two; struct memory * mm; }; typedef double** subseg; struct mesh { subseg *dummysub; }; double * returner(int*const* i, double *d) { (void)(i); return d; } void struct_null() { struct memory dm; float o = 99; float * oo = &o; float ** ooo = &oo; dm.oop = ooo; struct memory * m = &dm; m->one = (int *)(NULL); m->two = (double *)(NULL); m->mm = (struct memory *)(NULL); m->one = (void *)(NULL); m->two = (void *)(NULL); m->mm = (void *)(NULL); *(m->oop) = (int *) NULL ; (m->oop) = (int *) NULL ; (void)(dm); (void)(m); (void)summator(1,34.4); (void)returner(0,0); double fd = 56; returner(0, &fd); (void)(fd); static const struct { const char *zPattern; const char *zDesc; } aTrans[] = { { "rchar: ", "Bytes received by read():" }, { "wchar: ", "Bytes sent to write():" }, { "syscr: ", "Read() system calls:" }, { "syscw: ", "Write() system calls:" }, { "read_bytes: ", "Bytes read from storage:" }, { "write_bytes: ", "Bytes written to storage:" }, { "cancelled_write_bytes: ", "Cancelled write bytes:" }, }; is_eq(strlen(aTrans[3].zPattern),7); is_streq(aTrans[2].zPattern, "syscr: "); is_streq(aTrans[1].zDesc,"Bytes sent to write():"); double d = 99; double * dd = &d; double **ddd = ⅆ *(ddd) = (int *) NULL; (void)(ddd); struct memorypool { int **nowblock; }; struct memorypool Vpool; int nowblock; int * s_nowblock = &nowblock; Vpool.nowblock = &s_nowblock; is_not_null(*Vpool.nowblock); *(Vpool.nowblock) = NULL; struct memorypool *pool = &Vpool; if (*(pool->nowblock) == (int *) NULL) { pass("ok"); } mm.aa = 42; is_eq(mm.aa,42); struct mesh msh; subseg sub[10]; for (int i=0;i<10;i++){sub[i] = (subseg)(ddd);} msh.dummysub = sub; struct mesh *ms = &msh; ms->dummysub[2] = (subseg) NULL; (void)(ms); pass("ok"); } union STRS{ double d; struct { double d; } T; }; void struct_inside_union() { union STRS s; s.T.d = 10.0; is_true(s.d != 0); } typedef int pointx; typedef struct { pointx x; int y; } Point2; const Point2 p2[] = { { .y = 4, .x = 5 } }; const Point2* getPoint(int index) { return &(p2[index]); } typedef unsigned char pcre_uchar; typedef unsigned char pcre_uint8; typedef unsigned int pcre_uint32; typedef struct spu { pcre_uchar *hvm; } spu; void pointer_arithm_in_struct() { pcre_uchar str[] = "abcd"; spu s; spu *ps = &s; ps->hvm = &str[1]; is_true(ps->hvm == &str[1]); ps->hvm += 2; is_true(ps->hvm == &str[3]); } typedef struct pcre_extra { unsigned long int flags; void *study_data; unsigned long int match_limit; void *callout_data; const unsigned char *tables; unsigned long int match_limit_recursion; unsigned char **mark; void *executable_jit; } pcre_extra; typedef struct pcre_study_data { pcre_uint32 size; pcre_uint32 flags; pcre_uint8 start_bits[32]; pcre_uint32 minlength; } pcre_study_data; void test_mark() { pcre_extra *extra = NULL; pcre_study_data *study; pcre_uint8 *markptr; void * allocated = malloc(sizeof(pcre_extra) + sizeof(pcre_study_data)); extra = (pcre_extra *)allocated; study = (pcre_study_data *)((char *)extra + sizeof(pcre_extra)); memset(study->start_bits, 0, 32 * sizeof(pcre_uint8)); extra->study_data = study; study->size = sizeof(pcre_study_data); extra->mark = &markptr; is_eq(study->size, 44); for (int i=0; i<32; i++) is_eq(study->start_bits[i], 0); } int main() { plan(104); struct programming variable; char *s = "Programming in Software Development."; variable.constant = 1.23; variable.pointer = s; is_eq(variable.constant, 1.23); is_streq(variable.pointer, "Programming in Software Development."); pass_by_val(variable); pass_by_ref(&variable); struct mainStruct s1; s1.constant = 42.; is_eq(s1.constant, 42.); secondStruct s2; s2.constant = 42.; is_eq(s2.constant, 42.); ts_c c; c.t = 42.; is_eq(c.t , 42.); tt1 t1; t1.v1 = 42.; is_eq(t1.v1,42.) tt2 t2; t2.v1 = 42.; is_eq(t2.v1,42.) struct ff tf2; tf2.v2 = t1.v1; is_eq(tf2.v2,t1.v1); struct outer o; o.i = 12; o.inner.j = 34; is_eq(o.i + o.inner.j, 46); struct xx x; x.i = 12; x.inner.j = 34; x.inner.deep.k = 56; is_eq(x.i + x.inner.j + x.inner.deep.k, 102); struct u{ int y; }; struct u yy; yy.y = 42; is_eq(yy.y,42); diag("Typedef struct with same name") { typedef struct Uq Uq; struct Uq{ int uq; }; Uq uu; uu.uq = 42; is_eq(uu.uq,42); } diag("Initialization of struct") struct Point { int x; int y; }; struct Point p = { .y = 2, .x = 3 }; is_eq(p.x, 3); is_eq(p.y, 2); diag("Initialization of a const struct pointer") const Point2* pp2 = getPoint(0); int pointSum = pp2->x + pp2->y; is_eq(pointSum, 9); diag("ImplicitValueInitExpr") { typedef struct { int x2; int y2; } coord2; typedef struct { coord2 position2; int possibleSteps2; } extCoord2; extCoord2 followingSteps[2] = { {.possibleSteps2 = 1}, {.possibleSteps2 = 1}, }; is_eq(followingSteps[0].possibleSteps2, 1); } { struct coord{ int x; int y; }; struct extCoord{ struct coord position; int possibleSteps; }; struct extCoord followingSteps[2] = { {.possibleSteps = 1}, {.possibleSteps = 1}, }; is_eq(followingSteps[0].possibleSteps, 1); } diag("Double typedef type") { typedef int int2; typedef int2 int3; typedef int3 int4; is_eq((int)((int4)((int3)((int2)(42)))),42); } { typedef size_t size2; is_eq(((size2)((size_t)(56))),56.0) } { is_eq((size_t)(43),43); } diag("Function pointer inside struct") { struct F1{ int x; int (*f)(int, float); }; struct F1 f1; f1.x = 42; f1.f = summator; is_eq(f1.x,42); is_eq(f1.f(3,5),8); } { typedef struct { int x; int (*f)(int, float); } F2; F2 f2; f2.x = 42; f2.f = summator; is_eq(f2.x,42); is_eq(f2.f(3,5),8); } diag("typedef function") { typedef int ALIAS (int, float); ALIAS * f = summator; is_eq(f(3,5),8); } { typedef int ALIAS2 (int, float); ALIAS2 * f; f = summator; is_eq(f(3,5),8); } diag("typedef struct C C inside function") { typedef struct CCC CCC; struct CCC { float ff; }; CCC c; c.ff = 3.14; is_eq(c.ff,3.14); } typedef struct CP CP; struct CP { float ff; }; CP cp; cp.ff = 3.14; is_eq(cp.ff,3.14); diag("struct name from Go keyword") { struct chan {int i;}; struct chan UU; UU.i = 5; is_eq(UU.i,5);} { struct defer {int i;}; struct defer UU; UU.i = 5; is_eq(UU.i,5);} { struct fallthrough {int i;}; struct fallthrough UU; UU.i = 5; is_eq(UU.i,5);} { struct func {int i;}; struct func UU; UU.i = 5; is_eq(UU.i,5);} { struct go {int i;}; struct go UU; UU.i = 5; is_eq(UU.i,5);} { struct import {int i;}; struct import UU; UU.i = 5; is_eq(UU.i,5);} { struct interface {int i;}; struct interface UU; UU.i = 5; is_eq(UU.i,5);} { struct map {int i;}; struct map UU; UU.i = 5; is_eq(UU.i,5);} { struct package {int i;}; struct package UU; UU.i = 5; is_eq(UU.i,5);} { struct range {int i;}; struct range UU; UU.i = 5; is_eq(UU.i,5);} { struct select {int i;}; struct select UU; UU.i = 5; is_eq(UU.i,5);} { struct type {int i;}; struct type UU; UU.i = 5; is_eq(UU.i,5);} { struct var {int i;}; struct var UU; UU.i = 5; is_eq(UU.i,5);} { struct _ {int i;}; struct _ UU; UU.i = 5; is_eq(UU.i,5);} { struct init {int i;}; struct init UU; UU.i = 5; is_eq(UU.i,5);} { struct len {int i;}; struct len UU; UU.i = 5; is_eq(UU.i,5);} { struct copy {int i;}; struct copy UU; UU.i = 5; is_eq(UU.i,5);} { struct fmt {int i;}; struct fmt UU; UU.i = 5; is_eq(UU.i,5);} { struct cap {int i;}; struct cap UU; UU.i = 5; is_eq(UU.i,5);} // uncomment after success implementation of struct scope // https://github.com/elliotchance/c2go/issues/368 /* diag("Typedef struct name from Go keyword") { typedef struct {int i;} chan ; chan UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} defer ; defer UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} fallthrough ; fallthrough UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} func ; func UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} go ; go UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} import ; import UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} interface ; interface UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} map ; map UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} package ; package UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} range ; range UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} select ; select UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} type ; type UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} var ; var UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} _ ; _ UU; UU.i = 5; is_eq(UU.i,5);} { typedef struct {int i;} init ; init UU; UU.i = 5; is_eq(UU.i,5);} */ struct_with_rec_fuction(); diag("name of struct inside struct") { typedef struct TI TI; struct TI{ TI *left, *right; double varTI; }; TI t1; t1.varTI = 4.3; TI t2; t2.varTI = 4.1; TI tt; tt.left = &t1; (*tt.left).right = &t2; tt.right = &t2; is_eq((*tt.left ).varTI, 4.3); is_eq((*(*tt.left).right).varTI, 4.1); is_eq((*tt.right ).varTI, 4.1); } struct_in_struct_with_star(); struct_null(); func_in_func_in_struct(); struct_inside_union(); pointer_arithm_in_struct(); test_mark(); done_testing(); } c2go-0.26.10/tests/switch.c000066400000000000000000000211231410601753200153170ustar00rootroot00000000000000// This file tests the various forms of switch statement. // // We must be extra sensitive to the fact that switch fallthrough is handled // differently in C and Go. Break statements are removed and fallthrough // statements are added when necessary. // // It is worth mentioning that a SwitchStmt has a CompoundStmt item that // contains all of the cases. However, if the individual case are not enclosed // in a scope each of the case statements and their childen are part of the same // CompoundStmt. For example, the first switch statement below contains a // CompoundStmt with 12 children. #include #include #include "tests.h" void match_a_single_case() { switch (1) { case 0: fail("code should not reach here"); break; case 1: pass(__func__); break; case 2: fail("code should not reach here"); break; default: fail("code should not reach here"); break; } } void fallthrough_to_next_case() { switch (1) { case 0: fail("code should not reach here"); break; case 1: pass(__func__); case 2: pass(__func__); break; default: fail("code should not reach here"); break; } } void match_no_cases() { switch (1) { case 5: fail("code should not reach here"); break; case 2: fail("code should not reach here"); break; } } void match_default() { switch (1) { case 5: fail("code should not reach here"); break; case 2: fail("code should not reach here"); break; default: pass(__func__); break; } } void fallthrough_several_cases_including_default() { switch (1) { case 0: fail("code should not reach here"); case 1: pass(__func__); case 2: pass(__func__); default: pass(__func__); } } void fallthrough_several_midway_default() { for(int i=0; i<=3; i++) { int j = -1; int expected = -1; if(i==0) expected = 10; if(i==1) expected = 21; if(i==2) expected = 22; if(i==3) expected = 13; if(i==4) expected = 666; switch(i) { case 4: fail("code should not reach here"); case 0: default: j = i+10; break; case 1: case 2: j = i+20; break; } is_eq(j, expected); } } void goto_label(bool use_goto) { for (;;) { switch (0) { case 3: continue; case 0: if (use_goto) { for (;;) break; goto LABEL; fail("code should not reach here"); } else if (false) { goto LABELX; goto LABELY; fail("code should not reach here"); } /* other comment */ // some comment /* fallthrough */ LABELY: case 4: LABEL: printf("x"); case 1: pass(__func__); break; case 2: ; LABELX: default: fail("code should not reach here"); break; } break; } } void scoped_match_a_single_case() { switch (1) { case 0: { fail("code should not reach here"); break; } case 1: { pass(__func__); break; } case 2: { fail("code should not reach here"); break; } default: { fail("code should not reach here"); break; } } } void scoped_fallthrough_to_next_case() { switch (1) { case 0: { fail("code should not reach here"); break; } case 1: { pass(__func__); } case 2: { pass(__func__); break; } default: { fail("code should not reach here"); break; } } } void scoped_match_no_cases() { switch (1) { case 5: { fail("code should not reach here"); break; } case 2: { fail("code should not reach here"); break; } } } void scoped_match_default() { switch (1) { case 5: { fail("code should not reach here"); break; } case 2: { fail("code should not reach here"); break; } default: { pass(__func__); break; } } } void scoped_fallthrough_several_cases_including_default() { switch (1) { case 0: { fail("code should not reach here"); } case 1: { pass(__func__); } case 2: { pass(__func__); } default: { pass(__func__); } } } void scoped_fallthrough_several_midway_default() { for(int i=0; i<=3; i++) { int j = -1; int expected = -1; if(i==0) expected = 10; if(i==1) expected = 21; if(i==2) expected = 22; if(i==3) expected = 13; if(i==4) expected = 666; switch(i) { case 4: { fail("code should not reach here"); } case 0: {} default: { j = i+10; break; } case 1: {} case 2: { j = i+20; } } is_eq(j, expected); } } void scoped_goto_label(bool use_goto) { for (;;) { switch (0) { case 3: { continue; } case 0: { if (use_goto) { for (;;) { break; } goto LABEL; fail("code should not reach here"); } else if (false) { goto LABELX; goto LABELY; fail("code should not reach here"); } /* other comment */ // some comment /* fallthrough */ } LABELY: {} case 4: {} LABEL: { printf("x"); } case 1: { pass(__func__); break; } case 2: { int x = 0; printf("%d", x); break; } LABELX: {} default: { fail("code should not reach here"); break; } } break; } } typedef struct I67 I67; struct I67{ int x,y; }; void run( I67 * i ,int pos) { switch (pos) { case 0: (*i).x += 1; (*i).y += 1; break; case 1: (*i).x -= 1; (*i).y -= 1; break; } } void run_with_block( I67 * i ,int pos) { switch (pos) { case 0: { (*i).x += 1; (*i).y += 1; break; } case 1: { (*i).x -= 1; (*i).y -= 1; } break; case 2: (*i).x *= 1; (*i).y *= 1; break; default: (*i).x *= 10; (*i).y *= 10; } } void switch_issue67() { I67 i; i.x = 0; i.y = 0; run(&i, 0); is_eq(i.x, 1); is_eq(i.y, 1); run(&i, 1); is_eq(i.x, 0); is_eq(i.y, 0); run_with_block(&i,0); is_eq(i.x, 1); is_eq(i.y, 1); run_with_block(&i, 1); is_eq(i.x, 0); is_eq(i.y, 0); } void empty_switch() { int pos = 0; switch (pos){ } is_eq(pos,0); } void default_only_switch() { int pos = 0; switch (pos){ case -1: // empty case case -1-4: // empty case case (-1-4-4): // empty case case (-3): // empty case case -2: // empty case default: pos++; } is_eq(pos,1); } void switch_without_input() { int pos = 0; switch (0){ default: pos++; } is_eq(pos,1); } int main() { plan(37); match_a_single_case(); fallthrough_to_next_case(); match_no_cases(); match_default(); fallthrough_several_cases_including_default(); fallthrough_several_midway_default(); goto_label(false); goto_label(true); // For each of the tests above there will be identical cases that use scopes // for the case statements. scoped_match_a_single_case(); scoped_fallthrough_to_next_case(); scoped_match_no_cases(); scoped_match_default(); scoped_fallthrough_several_cases_including_default(); scoped_fallthrough_several_midway_default(); scoped_goto_label(false); scoped_goto_label(true); switch_issue67(); empty_switch(); default_only_switch(); switch_without_input(); done_testing(); } c2go-0.26.10/tests/syslog.c000066400000000000000000000004171410601753200153410ustar00rootroot00000000000000#include #include #include "tests.h" int main() { plan(0); openlog("c2go",LOG_PID|LOG_NDELAY,LOG_USER); setlogmask(LOG_UPTO(LOG_NOTICE)); int i = 1; double x = 2.71828; syslog(LOG_NOTICE,"hi there %d %f",i,x); closelog(); done_testing(); } c2go-0.26.10/tests/ternary.c000066400000000000000000000014661410601753200155120ustar00rootroot00000000000000#include #include "tests.h" void f_empty(){ return; }; int main() { plan(9); int a = 'a' == 65 ? 10 : 100; float b = 10 == 10 ? 1.0 : 2.0; char *c = 'x' == 5 ? "one" : "two"; char d = a == 100 ? 'x' : 1; is_eq(a, 100); is_eq(b, 1); is_streq(c, "two"); is_eq(d, 'x'); is_false(0 ? 1 : 0); is_false(NULL ? 1 : 0); is_true('x' ? 1 : 0); a = a == 10 ? b == 1.0 ? 1 : 2 : 2; if (a == (a == 2 ? 5 : 10)) { fail(__func__); } else { pass(__func__); } diag("CStyleCast ") {double a, b; 0 ? (void)(a) : (void)(b); (void)(a),(void)(b); } {double a ; 0 ? (void)(a) : f_empty(); (void)(a);} {double b; 0 ? f_empty() : (void)(b); (void)(b);} { ; 0 ? f_empty() : f_empty(); } pass("Ok - ToVoid"); done_testing(); } c2go-0.26.10/tests/tests.h000066400000000000000000000324061410601753200151730ustar00rootroot00000000000000#include // strlen() #include // signbit() #include // printf() // When comparing floating-point numbers this is how many significant bits will // be used to calculate the epsilon. #define INT64 52 - 4 #define INT32 23 - 4 // approx() is used to compare floating-point numbers. It will automatically // calculate a very small epsilon (the difference between the two values that is // still considered equal) based on the expected value and number of bits. // // approx() is used by the is_eq() macro for comparing numbers of any kind // which makes it ideal for comparing different sized floats or other math that // might introduce rounding errors. #define approx(actual, expected) approxf(actual, expected, \ sizeof(actual) != sizeof(expected) ? INT32 : INT64) // approxf() will strictly not handle any input value that is infinite or NaN. // It will always return false, even if the values are exactly equal. This is to // force you to use the correct matcher (ie. is_inf()) instead of relying on // comparisons which might not work. static int approxf(double actual, double expected, int bits) { // We do not handle infinities or NaN. if (isinf(actual) || isinf(expected) || isnan(actual) || isnan(expected)) { return 0; } // If we expect zero (a common case) we have a fixed epsilon from actual. If // allowed to continue the epsilon calculated would be zero and we would be // doing an exact match which is what we want to avoid. if (expected == 0.0) { return fabs(actual) < (1 / pow(2, bits)); } // The epsilon is calculated based on significant bits of the actual value. // The amount of bits used depends on the original size of the float (in // terms of bits) subtracting a few to allow for very slight rounding // errors. double epsilon = fabs(expected / pow(2, bits)); // The numbers are considered equal if the absolute difference between them // is less than the relative epsilon. return fabs(actual - expected) <= epsilon; } // isnegzero tests if a value is a negative zero. Negative zeros are a special // value of floating points that are equivalent in value, but not of bits to the // common 0.0 value. static int isnegzero(double x) { return (x * -0.0) == 0.0 && signbit(x); } // TAP: Below is a crude implementation of the TAP protocol for testing. If you // add any new functionality to this file that is not part of TAP you should // place that code above this comment. // The number for the current test. It is incremented before each check. static int current_test = 0; // The total number of tests expected to be run. This must be set with plan() // before any checks are performed. static int total_tests = 0; // The total number of failed tests. static int total_failures = 0; // Signals if the last test passed (1) or failed (0). static int last_test_was_ok = 1; // Set the number of expected tests/checks. This is important to prevent errors // that would cause the program to silently fail before the test suite is // finished. // // If the number of checks at the end (done_testing) is not the same as the // value provided here then the suite will fail. // // To avoid Gcc warning (unused-function), // force to call here the function isnegzero() #define plan(numberOfTests) \ isnegzero(1); \ total_tests = numberOfTests; \ printf("1..%d\n", numberOfTests) // Print a diagnotic message or comment. Comments make the output more // understandable (such as headings or descriptions) and can be printed at any // time. // // diag() takes the same format and arguments as a printf(). #define diag(...) \ printf("# "); \ printf(__VA_ARGS__); \ printf("\n"); // Check if the input is true. True in C is any value that is not a derivative // of zero (or NULL). Any other value, including negative values and fractions // are considered true. // // You should only use this when testing values that are integers or pointers. // Zero values in floating-points are not always reliable to compare exactly. #define is_true(actual) \ if (actual) \ { \ pass("%s", #actual) \ } \ else \ { \ fail("%s", #actual) \ } // Check if the input is false. This works in the exact opposite way as // is_true(). Be careful with floating-point values. #define is_false(actual) \ if (actual == 0) \ { \ pass("%s", #actual) \ } \ else \ { \ fail("%s", #actual) \ } // Immediately pass a check. This is useful if you are testing code flow, such // as reaching a particular if/else branch. // // pass() takes the same arguments as a printf(). #define pass(...) \ { \ ++current_test; \ printf("%d ok - ", current_test); \ printf(__VA_ARGS__); \ printf("\n"); \ last_test_was_ok = 1; \ } // Immediately fail a check. This is useful if you are testing code flow (such // as code that should not be reached or known bad conditions we met. // // fail() takes the same arguments as a printf(). #define fail(...) \ { \ ++current_test; \ ++total_failures; \ printf("%d not ok - %s:%d: ", current_test, __FILE__, __LINE__); \ printf(__VA_ARGS__); \ printf("\n"); \ last_test_was_ok = 0; \ } // Test if two values are equal. is_eq() will accept any *numerical* value than // can be cast to a double and compared. This does not work with strings, see // is_streq(). // // Floating-point values are notoriously hard to compare exactly so the values // are compared through the approx() function also defined in this file. #define is_eq(actual, expected) \ if (approx((actual), (expected))) \ { \ pass("%s == %s", #actual, #expected) \ } \ else \ { \ fail("%s == %s # got %.25g", #actual, #expected, (double)(actual)) \ } // This works in the opposite way as is_eq(). #define is_not_eq(actual, expected) \ if (approx((actual), (expected))) \ { \ fail("%s != %s # got %f", #actual, #expected, (double)(actual)) \ } \ else \ { \ pass("%s != %s", #actual, #expected) \ } // Compare two C strings. The two strings are equal if they are the same length // (based on strlen) and each of their characters (actually bytes) are exactly // the same value. This is nor to be used with strings that are mixed case or // contain multibyte characters (eg. UTF-16, etc). #define is_streq(actual, expected) \ if (strcmp(actual, expected) == 0) \ { \ pass("%s == %s", #actual, #expected) \ } \ else \ { \ fail("%s (%d b) == %s (%d b) # got \"%s\"", #actual, \ strlen(#actual), #expected, strlen(#expected), actual) \ } // Check that a floating-point value is Not A Number. Passing a value that is // not floating point may lead to undefined behaviour. #define is_nan(actual) \ if (isnan(actual)) \ { \ pass("isnan(%s)", #actual) \ } \ else \ { \ fail("isnan(%s) # got %f", #actual, actual) \ } // Check that a floating-point value is positive or negative infinity. A sign of // less than 0 will check for -inf and a sign greater than 0 will check for // +inf. A sign of 0 will always cause a failure. // // Mac and Linux check for infinity in different ways; either by using isinf() // or comparing directly with an INFINITY constant. We always use both methods. // This is separate checking the sign of the infinity. #define is_inf(actual, sign) \ { \ int linuxInf = ((actual) == -INFINITY || (actual) == INFINITY); \ int macInf = (isinf(actual) == 1); \ if ((linuxInf || macInf) && ((sign > 0 && (actual) > 0) || (sign < 0 && (actual) < 0))) \ { \ pass("isinf(%s, %d)", #actual, sign) \ } \ else \ { \ fail("isinf(%s, %d) # got %f", #actual, sign, actual) \ } \ } // Check that a value is a negative-zero. See isnegzero() for more information. // Using non-floating-point values with this may give unexpected results. #define is_negzero(actual) is_true(isnegzero(actual)); #define is_null(actual) \ if (actual == NULL) \ { \ pass("%s == NULL", #actual) \ } \ else \ { \ fail("%s == NULL", #actual) \ } #define is_not_null(actual) \ if (actual != NULL) \ { \ pass("%s != NULL", #actual) \ } \ else \ { \ fail("%s != NULL", #actual) \ } // disabled will suppress checks. The check, and any code associated within it // will not be run at all. This is not the same as passing or skipping a test. #define disabled(x) // To signal that testing is now complete and to return the appropriate status // code. This should be the last line in the main() function. #define done_testing() \ int exit_status = 0; \ if (total_failures > 0) \ { \ diag("FAILED: There was %d failed tests.", total_failures); \ exit_status = 101; \ } \ if (current_test != total_tests) \ { \ diag("FAILED: Expected %d tests, but ran %d.", total_tests, current_test); \ exit_status = 102; \ } \ /* If we exit (with any status) the Go code coverage will not be generated. */ \ if (exit_status != 0) { \ return exit_status; \ } \ return 0; // or_return will return (with an optional value provided) if the check failed. // // is_not_null(filePointer) or_return(); // #define or_return(...) \ if (!last_test_was_ok) \ { \ return __VA_ARGS__; \ } // Do not place code beyond this. See the TAP comment above. c2go-0.26.10/tests/time.c000066400000000000000000000041431410601753200147570ustar00rootroot00000000000000#include #include #include "tests.h" #define START_TEST(t) \ diag(#t); \ test_##t(); void test_time() { time_t now; time_t tloc; now = time(NULL); is_not_eq(now, 0); now = time(&tloc); is_not_eq(now, 0); is_eq(now, tloc); } void test_ctime() { char* s; // 1999-12-31 11:59:58 time_t now = 946670398; s = ctime(&now); is_not_null(s); // Hours/minutes will vary based on local time. Ignore them. s[11] = 'H'; s[12] = 'H'; s[14] = 'm'; s[15] = 'm'; is_streq(s, "Fri Dec 31 HH:mm:58 1999\n"); } void test_gmtime() { struct tm * timeinfo; time_t rawtime = 80000; timeinfo = gmtime ( &rawtime ); is_eq( timeinfo-> tm_sec , 20 ); is_eq( timeinfo-> tm_min , 13 ); is_eq( timeinfo-> tm_hour , 22 ); is_eq( timeinfo-> tm_mday , 1 ); is_eq( timeinfo-> tm_mon , 0 ); is_eq( timeinfo-> tm_year , 70 ); is_eq( timeinfo-> tm_wday , 4 ); is_eq( timeinfo-> tm_yday , 0 ); is_eq( timeinfo-> tm_isdst , 0 ); } void test_mktime() { struct tm timeinfo; timeinfo.tm_year = 2000 - 1900; timeinfo.tm_mon = 5 - 1 ; timeinfo.tm_mday = 20 ; timeinfo.tm_sec = 0 ; timeinfo.tm_min = 0 ; timeinfo.tm_hour = 0 ; mktime ( &timeinfo ); is_eq(timeinfo.tm_wday , 6 ); is_eq(timeinfo.tm_year , 100 ); is_eq(timeinfo.tm_mon , 4 ); is_eq(timeinfo.tm_mday , 20 ); } void test_asctime() { time_t rawtime = 80000; struct tm * timeinfo; timeinfo = gmtime ( &rawtime ); is_streq(asctime(timeinfo) , "Thu Jan 1 22:13:20 1970\n" ); } int main() { plan(19); // sorting in according to : // http://www.cplusplus.com/reference/ctime/clock/ START_TEST(asctime ); // TODO : START_TEST(clock ); START_TEST(ctime ); // TODO : START_TEST(difftime ); START_TEST(gmtime ); // TODO : START_TEST(localtime ); START_TEST(mktime ); // TODO : START_TEST(strftime ); START_TEST(time ); done_testing(); } c2go-0.26.10/tests/trigraph/000077500000000000000000000000001410601753200154735ustar00rootroot00000000000000c2go-0.26.10/tests/trigraph/main.c000066400000000000000000000002411410601753200165600ustar00rootroot00000000000000#include int main(){ // Trigraph tests require the `-trigraph` clang option, so it cannot be amount other general tests. printf("??="); return 0; } c2go-0.26.10/tests/unary.c000066400000000000000000000011611410601753200151540ustar00rootroot00000000000000#include #include "tests.h" #define START_TEST(t) \ diag(#t); \ test_##t(); void test_notint() { int i = 0; if (!i) { pass("good"); } else { fail("fail"); } i = 123; if (!i) { fail("fail"); } else { pass("good"); } } void test_notptr() { FILE *fp = NULL; if (!fp) { pass("good"); } else { fail("fail"); } fp = stdin; if (!fp) { fail("fail"); } else { pass("good"); } } int main() { plan(4); START_TEST(notint) START_TEST(notptr) done_testing(); } c2go-0.26.10/tests/union.c000066400000000000000000000076211410601753200151550ustar00rootroot00000000000000// Tests for unions. #include #include "tests.h" union programming { int constant; char *pointer; }; union programming init_var() { union programming variable; char *s = "Programming in Software Development."; variable.pointer = s; is_streq(variable.pointer, "Programming in Software Development."); variable.constant = 123; is_eq(variable.constant, 123); return variable; } void pass_by_ref(union programming *addr) { char *s = "Show string member."; int v = 123+456; addr->constant += 456; is_eq(addr->constant, v); addr->pointer = s; is_streq(addr->pointer, "Show string member."); } void var_by_val(union programming value) { value.constant++; is_eq(value.constant, 124); } struct SHA3 { union { double iY; double dY; } uY; float ffY; }; union unknown { double i2; double d2; }; struct SHA32 { union unknown u2; float ff2; }; void union_inside_struct() { diag("Union inside struct") struct SHA3 sha; sha.ffY = 12.444; sha.uY.iY = 4; is_eq(sha.uY.iY, 4); is_eq(sha.uY.dY, 4); is_eq(sha.ffY , 12.444); struct SHA32 sha2; sha2.ff2 = 12.444; sha2.u2.i2 = 4; is_eq(sha2.u2.i2, 4); is_eq(sha2.u2.d2, 4); is_eq(sha2.ff2 , 12.444); pass("ok"); } typedef union myunion myunion; typedef union myunion { double PI; int B; }MYUNION; typedef union { double PI; int B; }MYUNION2; void union_typedef() { diag("Typedef union") union myunion m; double v = 3.14; m.PI = v; is_eq(m.PI,3.14); is_true(m.B != 0); is_eq(v, 3.14); v += 1.0; is_eq(v, 4.14); is_eq(m.PI,3.14); MYUNION mm; mm.PI = 3.14; is_eq(mm.PI,3.14); is_true(mm.B != 0); myunion mmm; mmm.PI = 3.14; is_eq(mmm.PI,3.14); is_true(mmm.B != 0); MYUNION2 mmmm; mmmm.PI = 3.14; is_eq(mmmm.PI,3.14); is_true(mmmm.B != 0); } typedef struct FuncDestructor FuncDestructor; struct FuncDestructor { int i; }; typedef struct FuncDef FuncDef; struct FuncDef { int i; union { FuncDef *pHash; FuncDestructor *pDestructor; } u; }; void union_inside_struct2() { FuncDef f; FuncDestructor fd; fd.i = 100; f.u.pDestructor = &fd; FuncDestructor * p_fd = f.u.pDestructor; is_eq((*p_fd).i , 100); is_true(f.u.pHash != NULL); is_true(f.u.pDestructor != NULL); int vHash = (*f.u.pHash).i; is_eq(vHash , 100); is_eq((*f.u.pHash).i , 100); } union UPNT{ int * a; int * b; int * c; }; void union_pointers() { union UPNT u; int v = 32; u.a = &v; is_eq(*u.a,32); is_eq(*u.b,32); is_eq(*u.c,32); pass("ok") } union UPNTF{ int (*f1)(int); int (*f2)(int); }; int union_function(int a) { return a+1; } void union_func_pointers() { union UPNTF u; u.f1 = union_function; is_eq(u.f1(21), 22); is_eq(u.f2(21), 22); } union array_union { float a[2]; float b[2]; }; void union_array() { union array_union arr; arr.a[0] = 12; arr.b[1] = 14; is_eq( arr.a[0] , 12); is_eq( arr.a[1] , 14); is_eq( arr.b[0] , 12); is_eq( arr.b[1] , 14); } typedef int ii; typedef struct SHA SHA; struct SHA{ union { ii s[25]; unsigned char x[100]; } u; unsigned uuu; }; void union_arr_in_str() { SHA sha; sha.uuu = 15; is_eq(sha.uuu,15); for (int i = 0 ; i< 25;i++) sha.u.s[0] = 0; is_eq(sha.u.s[0],0); is_true(sha.u.x[0] == 0); for (int i=0;i<6;i++){ sha.u.s[i] = (ii)(4); sha.u.s[i] = (ii)(42) + sha.u.s[i]; } is_eq(sha.u.s[5],46); is_true(sha.u.x[0] != 0); } union un_struct{ struct { short a; short b; } str; long l; }; void union_with_struct() { union un_struct u; u.str.a = 12; u.str.b = 45; is_eq(u.str.a, 12); is_eq(u.str.b, 45); is_true( u.l > 0 ); } int main() { plan(46); union programming variable; variable = init_var(); var_by_val(variable); pass_by_ref(&variable); union_inside_struct(); union_typedef(); union_inside_struct2(); union_pointers(); union_func_pointers(); union_array(); union_arr_in_str(); union_with_struct(); done_testing(); } c2go-0.26.10/tests/while.c000066400000000000000000000034751410601753200151400ustar00rootroot00000000000000#include #include "tests.h" typedef float **triangle; #define deadtri(tria) ((tria)[1] == (triangle) NULL) int main() { plan(15); int value = 1; while (value <= 3) { pass("value is %d", value); value++; } // continue value = 0; while (value < 3) { value++; if (value < 3) continue; pass("%d", value); } diag("while without body") while(0); pass("%s","while without body"); value = 1; while((value--,value)); is_eq(value , 0); diag("while with star"); { int * ok; int value2; ok = & value2; *ok = 1; int iterator = 0; do{ if (iterator == 1){ *ok = 0; } iterator ++; if (iterator >10){ break; } }while(*ok); is_eq(*ok, 0); is_eq(iterator, 2); *ok = 1; iterator = 0; do{ iterator ++; if (iterator >10){ break; } }while(*ok); is_eq(*ok, 1); is_eq(iterator, 11); iterator = 0; do{ iterator ++; *ok = 0; if (iterator >10){ fail("execution should not reach here"); break; } continue; fail("execution should not reach here"); }while(*ok); is_eq(*ok, 0); is_eq(iterator, 1); iterator = 0; do{ iterator ++; *ok = 0; for (int i=0; i<5; i++) { iterator ++; continue; // this will only continue the inner loop } if (iterator >10){ fail("execution should not reach here"); break; } continue; fail("execution should not reach here"); }while(*ok); is_eq(*ok, 0); is_eq(iterator, 6); } diag("while with --"); { int T = 2; int counter = 0; while(T--){ if (counter > 50){ break; } }; is_eq(T,-1); } done_testing(); } c2go-0.26.10/transpiler/000077500000000000000000000000001410601753200146745ustar00rootroot00000000000000c2go-0.26.10/transpiler/binary.go000066400000000000000000000377511410601753200165240ustar00rootroot00000000000000// This file contains functions for transpiling binary operator expressions. package transpiler import ( "fmt" goast "go/ast" "go/token" "strings" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" ) // Comma problem. Example: // for (int i=0,j=0;i+=1,j<5;i++,j++){...} // For solving - we have to separate the // binary operator "," to 2 parts: // part 1(pre ): left part - typically one or more some expessions // part 2(stmt): right part - always only one expression, with or witout // logical operators like "==", "!=", ... func transpileBinaryOperatorComma(n *ast.BinaryOperator, p *program.Program) ( stmt goast.Stmt, preStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpile operator comma : err = %v", err) p.AddMessage(p.GenerateWarningMessage(err, n)) } }() left, err := transpileToStmts(n.Children()[0], p) if err != nil { return nil, nil, err } right, err := transpileToStmts(n.Children()[1], p) if err != nil { return nil, nil, err } if left == nil || right == nil { return nil, nil, fmt.Errorf("Cannot transpile binary operator comma: right = %v , left = %v", right, left) } preStmts = append(preStmts, left...) preStmts = append(preStmts, right...) if len(preStmts) >= 2 { return preStmts[len(preStmts)-1], preStmts[:len(preStmts)-1], nil } if len(preStmts) == 1 { return preStmts[0], nil, nil } return nil, nil, nil } func transpileBinaryOperator(n *ast.BinaryOperator, p *program.Program, exprIsStmt bool) ( expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpile BinaryOperator with type '%s' : result type = {%s}. Error: %v", n.Type, eType, err) p.AddMessage(p.GenerateWarningMessage(err, n)) } }() operator := getTokenForOperator(n.Operator) // Char overflow // BinaryOperator 0x2b74458 'int' '!=' // |-ImplicitCastExpr 0x2b74440 'int' // | `-ImplicitCastExpr 0x2b74428 'char' // | `-... // `-ParenExpr 0x2b74408 'int' // `-UnaryOperator 0x2b743e8 'int' prefix '-' // `-IntegerLiteral 0x2b743c8 'int' 1 if n.Operator == "!=" { var leftOk bool if l0, ok := n.ChildNodes[0].(*ast.ImplicitCastExpr); ok && l0.Type == "int" { if len(l0.ChildNodes) > 0 { if l1, ok := l0.ChildNodes[0].(*ast.ImplicitCastExpr); ok && l1.Type == "char" { leftOk = true } } } if leftOk { if r0, ok := n.ChildNodes[1].(*ast.ParenExpr); ok && r0.Type == "int" { if len(r0.ChildNodes) > 0 { if r1, ok := r0.ChildNodes[0].(*ast.UnaryOperator); ok && r1.IsPrefix && r1.Operator == "-" { if r2, ok := r1.ChildNodes[0].(*ast.IntegerLiteral); ok && r2.Type == "int" { r0.ChildNodes[0] = &ast.BinaryOperator{ Type: "int", Type2: "int", Operator: "+", ChildNodes: []ast.Node{ r1, &ast.IntegerLiteral{ Type: "int", Value: "256", }, }, } } } } } } } // Example of C code // a = b = 1 // // Operation equal transpile from right to left // Solving: // b = 1, a = b // // Operation comma tranpile from left to right // If we have for example: // a = b = c = 1 // then solution is: // c = 1, b = c, a = b // |-----------| // this part, created in according to // recursive working // Example of AST tree for problem: // |-BinaryOperator 0x2f17870 'int' '=' // | |-DeclRefExpr 0x2f177d8 'int' lvalue Var 0x2f176d8 'x' 'int' // | `-BinaryOperator 0x2f17848 'int' '=' // | |-DeclRefExpr 0x2f17800 'int' lvalue Var 0x2f17748 'y' 'int' // | `-IntegerLiteral 0x2f17828 'int' 1 // // Example of AST tree for solution: // |-BinaryOperator 0x368e8d8 'int' ',' // | |-BinaryOperator 0x368e820 'int' '=' // | | |-DeclRefExpr 0x368e7d8 'int' lvalue Var 0x368e748 'y' 'int' // | | `-IntegerLiteral 0x368e800 'int' 1 // | `-BinaryOperator 0x368e8b0 'int' '=' // | |-DeclRefExpr 0x368e848 'int' lvalue Var 0x368e6d8 'x' 'int' // | `-ImplicitCastExpr 0x368e898 'int' // | `-DeclRefExpr 0x368e870 'int' lvalue Var 0x368e748 'y' 'int' if getTokenForOperator(n.Operator) == token.ASSIGN { switch c := n.Children()[1].(type) { case *ast.BinaryOperator: if getTokenForOperator(c.Operator) == token.ASSIGN { bSecond := ast.BinaryOperator{ Type: c.Type, Operator: "=", } bSecond.AddChild(n.Children()[0]) var impl ast.ImplicitCastExpr impl.Type = c.Type impl.Kind = "LValueToRValue" impl.AddChild(c.Children()[0]) bSecond.AddChild(&impl) var bComma ast.BinaryOperator bComma.Operator = "," bComma.Type = c.Type bComma.AddChild(c) bComma.AddChild(&bSecond) // goast.NewBinaryExpr takes care to wrap any AST children safely in a closure, if needed. return transpileBinaryOperator(&bComma, p, exprIsStmt) } } } // Example of C code // a = 1, b = a // Solving // a = 1; // preStmts // b = a; // n // Example of AST tree for problem: // |-BinaryOperator 0x368e8d8 'int' ',' // | |-BinaryOperator 0x368e820 'int' '=' // | | |-DeclRefExpr 0x368e7d8 'int' lvalue Var 0x368e748 'y' 'int' // | | `-IntegerLiteral 0x368e800 'int' 1 // | `-BinaryOperator 0x368e8b0 'int' '=' // | |-DeclRefExpr 0x368e848 'int' lvalue Var 0x368e6d8 'x' 'int' // | `-ImplicitCastExpr 0x368e898 'int' // | `-DeclRefExpr 0x368e870 'int' lvalue Var 0x368e748 'y' 'int' // // Example of AST tree for solution: // |-BinaryOperator 0x21a7820 'int' '=' // | |-DeclRefExpr 0x21a77d8 'int' lvalue Var 0x21a7748 'y' 'int' // | `-IntegerLiteral 0x21a7800 'int' 1 // |-BinaryOperator 0x21a78b0 'int' '=' // | |-DeclRefExpr 0x21a7848 'int' lvalue Var 0x21a76d8 'x' 'int' // | `-ImplicitCastExpr 0x21a7898 'int' // | `-DeclRefExpr 0x21a7870 'int' lvalue Var 0x21a7748 'y' 'int' if getTokenForOperator(n.Operator) == token.COMMA { stmts, _, newPre, newPost, err := transpileToExpr(n.Children()[0], p, exprIsStmt) if err != nil { return nil, "unknown50", nil, nil, err } preStmts = append(preStmts, newPre...) preStmts = append(preStmts, util.NewExprStmt(stmts)) preStmts = append(preStmts, newPost...) var st string stmts, st, newPre, newPost, err = transpileToExpr(n.Children()[1], p, exprIsStmt) if err != nil { return nil, "unknown51", nil, nil, err } // Theoretically , we don't have any preStmts or postStmts // from n.Children()[1] if len(newPre) > 0 || len(newPost) > 0 { p.AddMessage(p.GenerateWarningMessage( fmt.Errorf("Not support length pre or post stmts: {%d,%d}", len(newPre), len(newPost)), n)) } return stmts, st, preStmts, postStmts, nil } left, leftType, newPre, newPost, err := atomicOperation(n.Children()[0], p) if err != nil { return nil, "unknown52", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) right, rightType, newPre, newPost, err := atomicOperation(n.Children()[1], p) if err != nil { return nil, "unknown53", nil, nil, err } var adjustPointerDiff int if types.IsPointer(p, leftType) && types.IsPointer(p, rightType) && (operator == token.SUB || operator == token.LSS || operator == token.GTR || operator == token.LEQ || operator == token.GEQ) { baseSize, err := types.SizeOf(p, types.GetBaseType(leftType)) if operator == token.SUB && err == nil && baseSize > 1 { adjustPointerDiff = baseSize } left, leftType, err = GetUintptrForPointer(p, left, leftType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } right, rightType, err = GetUintptrForPointer(p, right, rightType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } } if types.IsPointer(p, leftType) && types.IsPointer(p, rightType) && (operator == token.EQL || operator == token.NEQ) && leftType != "NullPointerType *" && rightType != "NullPointerType *" { left, leftType, err = GetUintptrForPointer(p, left, leftType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } right, rightType, err = GetUintptrForPointer(p, right, rightType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) returnType := types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType) if operator == token.LAND || operator == token.LOR { left, err = types.CastExpr(p, left, leftType, "bool") p.AddMessage(p.GenerateWarningOrErrorMessage(err, n, left == nil)) if left == nil { left = util.NewNil() } right, err = types.CastExpr(p, right, rightType, "bool") p.AddMessage(p.GenerateWarningOrErrorMessage(err, n, right == nil)) if right == nil { right = util.NewNil() } resolvedLeftType, err := types.ResolveType(p, leftType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } expr := util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt) return expr, "bool", preStmts, postStmts, nil } // The right hand argument of the shift left or shift right operators // in Go must be unsigned integers. In C, shifting with a negative shift // count is undefined behaviour (so we should be able to ignore that case). // To handle this, cast the shift count to a uint64. if operator == token.SHL || operator == token.SHR { right, err = types.CastExpr(p, right, rightType, "unsigned long long") p.AddMessage(p.GenerateWarningOrErrorMessage(err, n, right == nil)) if right == nil { right = util.NewNil() } return util.NewBinaryExpr(left, operator, right, "uint64", exprIsStmt), leftType, preStmts, postStmts, nil } // pointer arithmetic if types.IsPointer(p, n.Type) { if operator == token.ADD || operator == token.SUB { if types.IsPointer(p, leftType) { expr, eType, newPre, newPost, err = pointerArithmetic(p, left, leftType, right, rightType, operator) } else { expr, eType, newPre, newPost, err = pointerArithmetic(p, right, rightType, left, leftType, operator) } if err != nil { return } if expr == nil { return nil, "", nil, nil, fmt.Errorf("Expr is nil") } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) return } } if operator == token.NEQ || operator == token.EQL || operator == token.LSS || operator == token.GTR || operator == token.LEQ || operator == token.GEQ || operator == token.AND || operator == token.ADD || operator == token.SUB || operator == token.MUL || operator == token.QUO || operator == token.REM { // We may have to cast the right side to the same type as the left // side. This is a bit crude because we should make a better // decision of which type to cast to instead of only using the type // of the left side. if rightType != types.NullPointer { right, err = types.CastExpr(p, right, rightType, leftType) rightType = leftType p.AddMessage(p.GenerateWarningOrErrorMessage(err, n, right == nil)) } } if operator == token.ASSIGN { // Memory allocation is translated into the Go-style. allocSize := getAllocationSizeNode(p, n.Children()[1]) if allocSize != nil { right, newPre, newPost, err = generateAlloc(p, allocSize, leftType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) } else { right, err = types.CastExpr(p, right, rightType, returnType) if p.AddMessage(p.GenerateWarningMessage(err, n)) && right == nil { right = util.NewNil() } } } if operator == token.ADD_ASSIGN || operator == token.SUB_ASSIGN { right, err = types.CastExpr(p, right, rightType, returnType) } var resolvedLeftType = n.Type if !types.IsFunction(n.Type) && !types.IsTypedefFunction(p, n.Type) { resolvedLeftType, err = types.ResolveType(p, leftType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } } // Enum casting if operator != token.ASSIGN && strings.Contains(leftType, "enum") { left, err = types.CastExpr(p, left, leftType, "int") if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } } // Enum casting if operator != token.ASSIGN && strings.Contains(rightType, "enum") { right, err = types.CastExpr(p, right, rightType, "int") if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } } if left == nil { err = fmt.Errorf("left part of binary operation is nil. left : %#v", n.Children()[0]) p.AddMessage(p.GenerateWarningMessage(err, n)) return nil, "", nil, nil, err } if right == nil { err = fmt.Errorf("right part of binary operation is nil. right : %#v", n.Children()[1]) p.AddMessage(p.GenerateWarningMessage(err, n)) return nil, "", nil, nil, err } if adjustPointerDiff > 0 { expr := util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt) returnType = types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType) return util.NewBinaryExpr(expr, token.QUO, util.NewIntLit(adjustPointerDiff), returnType, exprIsStmt), returnType, preStmts, postStmts, nil } return util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt), types.ResolveTypeForBinaryOperator(p, n.Operator, leftType, rightType), preStmts, postStmts, nil } func foundCallExpr(n ast.Node) *ast.CallExpr { switch v := n.(type) { case *ast.ImplicitCastExpr, *ast.CStyleCastExpr: return foundCallExpr(n.Children()[0]) case *ast.CallExpr: return v } return nil } // getAllocationSizeNode returns the node that, if evaluated, would return the // size (in bytes) of a memory allocation operation. For example: // // (int *)malloc(sizeof(int)) // // Would return the node that represents the "sizeof(int)". // // If the node does not represent an allocation operation (such as calling // malloc, calloc, realloc, etc.) then nil is returned. // // In the case of calloc() it will return a new BinaryExpr that multiplies both // arguments. func getAllocationSizeNode(p *program.Program, node ast.Node) ast.Node { expr := foundCallExpr(node) if expr == nil || expr == (*ast.CallExpr)(nil) { return nil } functionName, _ := getNameOfFunctionFromCallExpr(p, expr) if functionName == "malloc" { // Is 1 always the body in this case? Might need to be more careful // to find the correct node. return expr.Children()[1] } if functionName == "calloc" { return &ast.BinaryOperator{ Type: "int", Operator: "*", ChildNodes: expr.Children()[1:], } } // TODO: realloc() is not supported // https://github.com/elliotchance/c2go/issues/118 // // Realloc will be treated as calloc which will almost certainly cause // bugs in your code. if functionName == "realloc" { return expr.Children()[2] } return nil } func generateAlloc(p *program.Program, allocSize ast.Node, leftType string) ( right goast.Expr, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { allocSizeExpr, allocType, newPre, newPost, err := transpileToExpr(allocSize, p, false) preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) if err != nil { return nil, preStmts, postStmts, err } toType, err := types.ResolveType(p, leftType) if err != nil { return nil, preStmts, postStmts, err } allocSizeExpr, err = types.CastExpr(p, allocSizeExpr, allocType, "int") if err != nil { return nil, preStmts, postStmts, err } right = util.NewCallExpr( "noarch.Malloc", allocSizeExpr, ) if toType != "unsafe.Pointer" { right = &goast.CallExpr{ Fun: &goast.ParenExpr{ X: util.NewTypeIdent(toType), }, Args: []goast.Expr{right}, } } return } c2go-0.26.10/transpiler/branch.go000066400000000000000000000550631410601753200164710ustar00rootroot00000000000000// This file contains functions for transpiling common branching and control // flow, such as "if", "while", "do" and "for". The more complicated control // flows like "switch" will be put into their own file of the same or sensible // name. package transpiler import ( "fmt" "go/token" goast "go/ast" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" "golang.org/x/tools/go/ast/astutil" ) func transpileIfStmt(n *ast.IfStmt, p *program.Program) ( *goast.IfStmt, []goast.Stmt, []goast.Stmt, error) { preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} children := n.Children() // With older versions of Clang there is always 4 or 5 children in an IfStmt. // For example: // // if (i == 0) { // return 0; // } else { // return 1; // } // // 1. Not sure what this is for. This gets removed. // 2. Not sure what this is for. // 3. conditional = BinaryOperator: i == 0 // 4. body = CompoundStmt: { return 0; } // 5. elseBody = CompoundStmt: { return 1; } // // elseBody will be nil if there is no else clause. // In Clang 9.0 (tested on Linux), an if-statement without an else has // exactly 2 children. // // 1. conditional = BinaryOperator: i == 0 // 2. body = CompoundStmt: { return 0; } // 3. (optional) else-body = CompoundStmt: { return 1; } // On linux I have seen only 4 children for an IfStmt with the same // definitions above, but missing the first argument. Since we don't // know what the first argument is for anyway we will just remove it on // Mac if necessary. if len(children) == 5 && children[0] != nil { panic("non-nil child 0 in IfStmt") } if len(children) == 5 { children = children[1:] } // Maybe we will discover what the nil value is? if len(children) == 4 && children[0] != nil { panic("non-nil child 0 in IfStmt") } if len(children) == 4 { children = children[1:] } // The last parameter must be false because we are transpiling an // expression - assignment operators need to be wrapped in closures. conditional, conditionalType, newPre, newPost, err := transpileToExpr(children[0], p, false) if err != nil { return nil, nil, nil, err } // null in C is false if conditionalType == types.NullPointer { conditional = util.NewIdent("false") conditionalType = "bool" } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) // The condition in Go must always be a bool. boolCondition, err := types.CastExpr(p, conditional, conditionalType, "bool") p.AddMessage(p.GenerateWarningOrErrorMessage(err, n, boolCondition == nil)) if boolCondition == nil { boolCondition = util.NewNil() } body, newPre, newPost, err := transpileToBlockStmt(children[1], p) if err != nil { return nil, nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) if body == nil { return nil, nil, nil, fmt.Errorf("Body of If cannot by nil") } if boolCondition == nil { return nil, nil, nil, fmt.Errorf("Bool Condition in If cannot by nil") } r := &goast.IfStmt{ Cond: boolCondition, Body: body, } if len(children) > 2 && children[2] != nil { elseBody, newPre, newPost, err := transpileToBlockStmt(children[2], p) if err != nil { return nil, nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) if elseBody != nil { r.Else = elseBody if _, ok := children[2].(*ast.IfStmt); ok { if len(elseBody.List) == 1 { r.Else = elseBody.List[0] } } } else { return nil, nil, nil, fmt.Errorf("Body of Else in If cannot be nil") } } return r, preStmts, postStmts, nil } func transpileForStmt(n *ast.ForStmt, p *program.Program) ( f goast.Stmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { // This `defer` is workaround // Please remove after solving all problems defer func() { if err != nil { err = fmt.Errorf("Cannot tranpile ForStmt: err = %v", err) p.AddMessage(p.GenerateWarningMessage(err, n)) } }() children := n.Children() // There are always 5 children in a ForStmt, for example: // // for ( c = 0 ; c < n ; c++ ) { // doSomething(); // } // // 1. initExpression = BinaryStmt: c = 0 // 2. Not sure what this is for, but it's always nil. There is a panic // below in case we discover what it is used for (pun intended). // 3. conditionalExpression = BinaryStmt: c < n // 4. stepExpression = BinaryStmt: c++ // 5. body = CompoundStmt: { CallExpr } if len(children) != 5 { panic(fmt.Sprintf("Expected 5 children in ForStmt, got %#v", children)) } // TODO: The second child of a ForStmt appears to always be null. // Are there any cases where it is used? if children[1] != nil { panic("non-nil child 1 in ForStmt") } switch c := children[0].(type) { case *ast.BinaryOperator: if c.Operator == "," { // If we have 2 and more initializations like // in operator for // for( a = 0, b = 0, c = 0; a < 5; a ++) // recursive action to code like that: // a = 0; // b = 0; // for(c = 0 ; a < 5 ; a++) before, newPre, newPost, err := transpileToStmt(children[0], p) if err != nil { return nil, nil, nil, err } preStmts = append(preStmts, combineStmts(before, newPre, newPost)...) children[0] = c.Children()[1] } case *ast.DeclStmt: { // If we have 2 and more initializations like // in operator for // for(int a = 0, b = 0, c = 0; a < 5; a ++) newPre, err := transpileToStmts(children[0], p) if err != nil { return nil, nil, nil, err } children[0] = nil preStmts = append(preStmts, newPre...) } } init, newPre, newPost, err := transpileToStmt(children[0], p) if err != nil { return nil, nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) // If we have 2 and more increments // in operator for // for( a = 0; a < 5; a ++, b++, c+=2) switch c := children[3].(type) { case *ast.BinaryOperator: if c.Operator == "," { // recursive action to code like that: // a = 0; // b = 0; // for(a = 0 ; a < 5 ; ){ // body // a++; // b++; // c+=2; // } // var compound *ast.CompoundStmt if children[4] != nil { // if body is exist if _, ok := children[4].(*ast.CompoundStmt); !ok { compound = new(ast.CompoundStmt) compound.AddChild(children[4]) } else { compound = children[4].(*ast.CompoundStmt) } } else { // if body is not exist compound = new(ast.CompoundStmt) } compound.ChildNodes = append(compound.Children(), c.Children()[0:len(c.Children())]...) children[4] = compound children[3] = nil } } var post goast.Stmt var transpilate bool if v, ok := children[3].(*ast.UnaryOperator); ok { if vv, ok := v.Children()[0].(*ast.DeclRefExpr); ok { if !types.IsPointer(p, vv.Type) && !types.IsFunction(vv.Type) { switch v.Operator { case "++": // for case: // for(...;...;i++)... post = &goast.IncDecStmt{ X: util.NewIdent(vv.Name), Tok: token.INC, } transpilate = true case "--": // for case: // for(...;...;i--)... post = &goast.IncDecStmt{ X: util.NewIdent(vv.Name), Tok: token.DEC, } transpilate = true } } } } if !transpilate { post, newPre, newPost, err = transpileToStmt(children[3], p) if err != nil { return nil, nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) } // If we have 2 and more conditions // in operator for // for( a = 0; b = c, b++, a < 5; a ++) switch c := children[2].(type) { case *ast.BinaryOperator: if c.Operator == "," { // recursive action to code like that: // a = 0; // b = 0; // for(a = 0 ; ; c+=2){ // b = c; // b++; // if (!(a < 5)) // break; // body // } tempSlice := c.Children()[0 : len(c.Children())-1] var condition ast.IfStmt condition.AddChild(nil) var par ast.ParenExpr par.Type = "bool" par.AddChild(c.Children()[len(c.Children())-1]) var unitary ast.UnaryOperator unitary.Type = "bool" unitary.AddChild(&par) unitary.Operator = "!" condition.AddChild(&unitary) var c ast.CompoundStmt c.AddChild(&ast.BreakStmt{}) condition.AddChild(&c) condition.AddChild(nil) tempSlice = append(tempSlice, &condition) var compound *ast.CompoundStmt if children[4] != nil { // if body is exist compound = children[4].(*ast.CompoundStmt) } else { // if body is not exist compound = new(ast.CompoundStmt) } compound.ChildNodes = append(tempSlice, compound.Children()...) children[4] = compound children[2] = nil } } // The condition can be nil. This means an infinite loop and will be // rendered in Go as "for {". var condition goast.Expr if children[2] != nil { var conditionType string var newPre, newPost []goast.Stmt // The last parameter must be false because we are transpiling an // expression - assignment operators need to be wrapped in closures. condition, conditionType, newPre, newPost, err = atomicOperation(children[2], p) if err != nil { return nil, nil, nil, err } // null in C is false if conditionType == types.NullPointer { condition = util.NewIdent("false") conditionType = "bool" } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) condition, err = types.CastExpr(p, condition, conditionType, "bool") p.AddMessage(p.GenerateWarningOrErrorMessage(err, n, condition == nil)) if condition == nil { condition = util.NewNil() } } body, newPre, newPost, err := transpileToBlockStmt(children[4], p) if err != nil { return nil, nil, nil, err } if body == nil { return nil, nil, nil, fmt.Errorf("Body of For cannot be nil") } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) // avoid extra block around FOR if len(preStmts) == 0 && len(postStmts) == 0 { return &goast.ForStmt{ Init: init, Cond: condition, Post: post, Body: body, }, preStmts, postStmts, nil } // for avoid dublication of init values for // case with 2 for`s var block goast.BlockStmt var forStmt = goast.ForStmt{ Init: init, Cond: condition, Post: post, Body: body, } block.List = combineStmts(&forStmt, preStmts, postStmts) block.Lbrace = 1 return &block, nil, nil, nil } // transpileWhileStmt - transpiler for operator While. // We have only operator FOR in Go, but in C we also have // operator WHILE. So, we have to convert to operator FOR. // We choose directly conversion from AST C code to AST C code, for // - avoid dublicate of code in realization WHILE and FOR. // - create only one operator FOR powerful. // Example of C code with operator WHILE: // while(i > 0){ // printf("While: %d\n",i); // i--; // } // AST for that code: // |-WhileStmt 0x2530a10 // | |-<<>> // | |-BinaryOperator 0x25307f0 'int' '>' // | | |-ImplicitCastExpr 0x25307d8 'int' // | | | `-DeclRefExpr 0x2530790 'int' lvalue Var 0x25306f8 'i' 'int' // | | `-IntegerLiteral 0x25307b8 'int' 0 // | `-CompoundStmt 0x25309e8 // | |-CallExpr 0x2530920 'int' // | | |-ImplicitCastExpr 0x2530908 'int (*)(const char *, ...)' // | | | `-DeclRefExpr 0x2530818 'int (const char *, ...)' Function 0x2523ee8 'printf' 'int (const char *, ...)' // | | |-ImplicitCastExpr 0x2530970 'const char *' // | | | `-ImplicitCastExpr 0x2530958 'char *' // | | | `-StringLiteral 0x2530878 'char [11]' lvalue "While: %d\n" // | | `-ImplicitCastExpr 0x2530988 'int' // | | `-DeclRefExpr 0x25308b0 'int' lvalue Var 0x25306f8 'i' 'int' // | `-UnaryOperator 0x25309c8 'int' postfix '--' // | `-DeclRefExpr 0x25309a0 'int' lvalue Var 0x25306f8 'i' 'int' // // Example of C code with operator FOR: // for (;i > 0;){ // printf("For: %d\n",i); // i--; // } // AST for that code: // |-ForStmt 0x2530d08 // | |-<<>> // | |-<<>> // | |-BinaryOperator 0x2530b00 'int' '>' // | | |-ImplicitCastExpr 0x2530ae8 'int' // | | | `-DeclRefExpr 0x2530aa0 'int' lvalue Var 0x25306f8 'i' 'int' // | | `-IntegerLiteral 0x2530ac8 'int' 0 // | |-<<>> // | `-CompoundStmt 0x2530ce0 // | |-CallExpr 0x2530bf8 'int' // | | |-ImplicitCastExpr 0x2530be0 'int (*)(const char *, ...)' // | | | `-DeclRefExpr 0x2530b28 'int (const char *, ...)' Function 0x2523ee8 'printf' 'int (const char *, ...)' // | | |-ImplicitCastExpr 0x2530c48 'const char *' // | | | `-ImplicitCastExpr 0x2530c30 'char *' // | | | `-StringLiteral 0x2530b88 'char [9]' lvalue "For: %d\n" // | | `-ImplicitCastExpr 0x2530c60 'int' // | | `-DeclRefExpr 0x2530bb8 'int' lvalue Var 0x25306f8 'i' 'int' // | `-UnaryOperator 0x2530ca0 'int' postfix '--' // | `-DeclRefExpr 0x2530c78 'int' lvalue Var 0x25306f8 'i' 'int' func transpileWhileStmt(n *ast.WhileStmt, p *program.Program) ( goast.Stmt, []goast.Stmt, []goast.Stmt, error) { // Skip first nil-child if present. children := n.Children() if len(children) == 3 && children[0] == nil { children = children[1:] } var forOperator ast.ForStmt forOperator.AddChild(nil) forOperator.AddChild(nil) forOperator.AddChild(children[0]) forOperator.AddChild(nil) if children[1] == nil { // added for case if WHILE haven't body, for example: // while(0); children[1] = &ast.CompoundStmt{} } forOperator.AddChild(children[1]) return transpileForStmt(&forOperator, p) } // transpileDoStmt - transpiler for operator Do...While // We have only operators FOR and IF in Go, but in C we also have // operator DO...WHILE. So, we have to convert to operators FOR and IF. // We choose directly conversion from AST C code to AST C code, for: // - avoid dublicate of code in realization DO...WHILE and FOR. // - create only one powerful operator FOR. // Example of C code with operator DO...WHILE: // do{ // printf("While: %d\n",i); // i--; // }while(i > 0); // AST for that code: // |-DoStmt 0x3bb1a68 // | |-CompoundStmt 0x3bb19b8 // | | |-CallExpr 0x3bb18f0 'int' // | | | |-ImplicitCastExpr 0x3bb18d8 'int (*)(const char *, ...)' // | | | | `-DeclRefExpr 0x3bb17e0 'int (const char *, ...)' Function 0x3ba4ee8 'printf' 'int (const char *, ...)' // | | | |-ImplicitCastExpr 0x3bb1940 'const char *' // | | | | `-ImplicitCastExpr 0x3bb1928 'char *' // | | | | `-StringLiteral 0x3bb1848 'char [11]' lvalue "While: %d\n" // | | | `-ImplicitCastExpr 0x3bb1958 'int' // | | | `-DeclRefExpr 0x3bb1880 'int' lvalue Var 0x3bb16f8 'i' 'int' // | | `-UnaryOperator 0x3bb1998 'int' postfix '--' // | | `-DeclRefExpr 0x3bb1970 'int' lvalue Var 0x3bb16f8 'i' 'int' // | `-BinaryOperator 0x3bb1a40 'int' '>' // | |-ImplicitCastExpr 0x3bb1a28 'int' // | | `-DeclRefExpr 0x3bb19e0 'int' lvalue Var 0x3bb16f8 'i' 'int' // | `-IntegerLiteral 0x3bb1a08 'int' 0 // // Example of C code with operator FOR: // for(;;){ // printf("For: %d\n",i); // i--; // if(!(i>0)){ // break; // } // } // AST for that code: // |-ForStmt 0x3bb1e08 // | |-<<>> // | |-<<>> // | |-<<>> // | |-<<>> // | `-CompoundStmt 0x3bb1dd8 // | |-CallExpr 0x3bb1bc8 'int' // | | |-ImplicitCastExpr 0x3bb1bb0 'int (*)(const char *, ...)' // | | | `-DeclRefExpr 0x3bb1af8 'int (const char *, ...)' Function 0x3ba4ee8 'printf' 'int (const char *, ...)' // | | |-ImplicitCastExpr 0x3bb1c18 'const char *' // | | | `-ImplicitCastExpr 0x3bb1c00 'char *' // | | | `-StringLiteral 0x3bb1b58 'char [9]' lvalue "For: %d\n" // | | `-ImplicitCastExpr 0x3bb1c30 'int' // | | `-DeclRefExpr 0x3bb1b88 'int' lvalue Var 0x3bb16f8 'i' 'int' // | |-UnaryOperator 0x3bb1c70 'int' postfix '--' // | | `-DeclRefExpr 0x3bb1c48 'int' lvalue Var 0x3bb16f8 'i' 'int' // | `-IfStmt 0x3bb1da8 // | |-<<>> // | |-UnaryOperator 0x3bb1d60 'int' prefix '!' // | | `-ParenExpr 0x3bb1d40 'int' // | | `-BinaryOperator 0x3bb1d18 'int' '>' // | | |-ImplicitCastExpr 0x3bb1d00 'int' // | | | `-DeclRefExpr 0x3bb1c90 'int' lvalue Var 0x3bb16f8 'i' 'int' // | | `-IntegerLiteral 0x3bb1ce0 'int' 0 // | |-CompoundStmt 0x3bb1d88 // | | `-BreakStmt 0x3bb1d80 // | `-<<>> func transpileDoStmt(n *ast.DoStmt, p *program.Program) ( f goast.Stmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { var forOperator ast.ForStmt forOperator.AddChild(nil) forOperator.AddChild(nil) forOperator.AddChild(nil) forOperator.AddChild(nil) var c *ast.CompoundStmt if _, ok := n.Children()[0].(*ast.CompoundStmt); ok { c = n.Children()[0].(*ast.CompoundStmt) } else { var newComp ast.CompoundStmt newComp.AddChild(n.Children()[0]) c = &newComp } ifBreak := createIfWithNotConditionAndBreak(n.Children()[1]) c.AddChild(&ifBreak) forOperator.AddChild(c) f, preStmts, postStmts, err = transpileForStmt(&forOperator, p) if hasContinueStmt(f) { adaptContinueStmt(f, p) } return } type continueDetector struct { level int forLevel []int hasContinue bool } func (c *continueDetector) Visit(node goast.Node) goast.Visitor { if node == nil { if len(c.forLevel) > 0 && c.level == c.forLevel[len(c.forLevel)-1] { // we are exiting a for loop c.forLevel = c.forLevel[:len(c.forLevel)-1] } c.level-- return nil } c.level++ switch n := node.(type) { case *goast.ForStmt: if len(c.forLevel) > 0 { // Do not look for continue within an inner for loop c.level-- return nil } // we have found the outer for loop c.forLevel = append(c.forLevel, c.level) case *goast.RangeStmt: // Do not look for continue within the children of this AST node type, // since a continue would refer to it and not the outer for loop. c.level-- return nil case *goast.BranchStmt: // only look for continue within the outer for loop if n.Tok == token.CONTINUE && len(c.forLevel) > 0 { c.hasContinue = true } } return c } func hasContinueStmt(e goast.Stmt) bool { var c continueDetector goast.Walk(&c, e) return c.hasContinue } func adaptContinueStmt(e goast.Stmt, p *program.Program) { var ( level int forLevel []int beforeConditionLabel string ) funcTransformBreak := func(cursor *astutil.Cursor) bool { level++ node := cursor.Node() switch n := node.(type) { case *goast.BranchStmt: // only replace continue within the outer for loop if n.Tok == token.CONTINUE && len(forLevel) > 0 { if beforeConditionLabel == "" { panic("Before condition label not set") } cursor.Replace(&goast.BranchStmt{ Label: util.NewIdent(beforeConditionLabel), Tok: token.GOTO, }) } case *goast.ForStmt: if len(forLevel) > 0 { // Do not look for continue within an inner for loop level-- return false } // we have found the outer for loop forLevel = append(forLevel, level) beforeConditionLabel = setConditionLabel(n, p) return true case *goast.RangeStmt: // Do not look for continue within the children of this AST node type, // since a continue would refer to it and not the outer for loop. level-- return false } return true } postFunc := func(cursor *astutil.Cursor) bool { if len(forLevel) > 0 && level == forLevel[len(forLevel)-1] { // we are exiting a for loop forLevel = forLevel[:len(forLevel)-1] } level-- return true } // Replace continue's with goto doWhileCondLabel astutil.Apply(e, funcTransformBreak, postFunc) } func setConditionLabel(f *goast.ForStmt, p *program.Program) (label string) { if f.Body == nil || len(f.Body.List) == 0 { return "" } lastStmt := f.Body.List[len(f.Body.List)-1] if _, ok := lastStmt.(*goast.IfStmt); ok { doWhileCondLabel := p.GetNextIdentifier("DO_WHILE_COND_LABEL_") f.Body.List[len(f.Body.List)-1] = &goast.LabeledStmt{ Label: util.NewIdent(doWhileCondLabel), Stmt: lastStmt, } return doWhileCondLabel } return "" } // createIfWithNotConditionAndBreak - create operator IF like on next example // of C code: // if ( !(condition) ) { // break; // } // Example of AST tree: // `-IfStmt 0x3bb1da8 // |-<<>> // |-UnaryOperator 0x3bb1d60 'int' prefix '!' // | `-ParenExpr 0x3bb1d40 'int' // | `- CONDITION // |-CompoundStmt 0x3bb1d88 // | `-BreakStmt 0x3bb1d80 // `-<<>> func createIfWithNotConditionAndBreak(condition ast.Node) (ifStmt ast.IfStmt) { ifStmt.AddChild(nil) var par ast.ParenExpr var unitary ast.UnaryOperator switch con := condition.(type) { case *ast.BinaryOperator: par.Type = con.Type unitary.Type = con.Type case *ast.ImplicitCastExpr: par.Type = con.Type unitary.Type = con.Type case *ast.CStyleCastExpr: par.Type = con.Type unitary.Type = con.Type case *ast.ParenExpr: par.Type = con.Type unitary.Type = con.Type case *ast.UnaryOperator: par.Type = con.Type unitary.Type = con.Type case *ast.IntegerLiteral: par.Type = con.Type unitary.Type = con.Type default: panic( fmt.Errorf("Type %T is not implemented in createIfWithNotConditionAndBreak", condition)) } par.AddChild(condition) unitary.Operator = "!" unitary.AddChild(&par) ifStmt.AddChild(&unitary) var c ast.CompoundStmt c.AddChild(&ast.BreakStmt{}) ifStmt.AddChild(&c) ifStmt.AddChild(nil) return } func transpileContinueStmt(n *ast.ContinueStmt, p *program.Program) (*goast.BranchStmt, error) { return &goast.BranchStmt{ Tok: token.CONTINUE, }, nil } c2go-0.26.10/transpiler/call.go000066400000000000000000000331261410601753200161430ustar00rootroot00000000000000// This file contains functions for transpiling function calls (invocations). package transpiler import ( "bytes" "fmt" "strings" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" goast "go/ast" "go/parser" "go/printer" "go/token" ) func getMemberName(firstChild ast.Node) (name string, ok bool) { switch fc := firstChild.(type) { case *ast.MemberExpr: return fc.Name, true case *ast.ParenExpr: return getMemberName(fc.Children()[0]) case *ast.ImplicitCastExpr: return getMemberName(fc.Children()[0]) case *ast.CStyleCastExpr: return getMemberName(fc.Children()[0]) } return "", false } func getName(p *program.Program, firstChild ast.Node) (name string, err error) { switch fc := firstChild.(type) { case *ast.DeclRefExpr: return fc.Name, nil case *ast.MemberExpr: if isUnionMemberExpr(p, fc) { var expr goast.Expr expr, _, _, _, err = transpileToExpr(fc, p, false) if err != nil { return } var buf bytes.Buffer err = printer.Fprint(&buf, token.NewFileSet(), expr) if err != nil { return } return buf.String(), nil } if len(fc.Children()) == 0 { return fc.Name, nil } var n string n, err = getName(p, fc.Children()[0]) if err != nil { return } return n + "." + fc.Name, nil case *ast.ParenExpr: return getName(p, fc.Children()[0]) case *ast.UnaryOperator: return getName(p, fc.Children()[0]) case *ast.ImplicitCastExpr: return getName(p, fc.Children()[0]) case *ast.CStyleCastExpr: return getName(p, fc.Children()[0]) case *ast.ArraySubscriptExpr: var expr goast.Expr expr, _, _, _, err = transpileArraySubscriptExpr(fc, p, false) if err != nil { return } var buf bytes.Buffer err = printer.Fprint(&buf, token.NewFileSet(), expr) if err != nil { return } return buf.String(), nil } return "", fmt.Errorf("cannot getName for: %#v", firstChild) } func getNameOfFunctionFromCallExpr(p *program.Program, n *ast.CallExpr) (string, error) { // The first child will always contain the name of the function being // called. firstChild, ok := n.Children()[0].(*ast.ImplicitCastExpr) if !ok { err := fmt.Errorf("unable to use CallExpr: %#v", n.Children()[0]) return "", err } return getName(p, firstChild.Children()[0]) } // transpileCallExpr transpiles expressions that calls a function, for example: // // foo("bar") // // It returns three arguments; the Go AST expression, the C type (that is // returned by the function) and any error. If there is an error returned you // can assume the first two arguments will not contain any useful information. func transpileCallExpr(n *ast.CallExpr, p *program.Program) ( _ *goast.CallExpr, resultType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Error in transpileCallExpr : %v", err) } }() functionName, err := getNameOfFunctionFromCallExpr(p, n) if err != nil { return nil, "", nil, nil, err } functionName = util.ConvertFunctionNameFromCtoGo(functionName) if functionName == "__builtin_va_start" || functionName == "__builtin_va_end" { // ignore function __builtin_va_start, __builtin_va_end // see "Variadic functions" return nil, "", nil, nil, nil } // function "calloc" from stdlib.c if functionName == "calloc" && len(n.Children()) == 3 { var allocType string size, _, preStmts, postStmts, err := transpileToExpr(n.Children()[1], p, false) if err != nil { return nil, "", nil, nil, err } if v, ok := n.Children()[2].(*ast.UnaryExprOrTypeTraitExpr); ok { allocType = v.Type2 } else { return nil, "", nil, nil, fmt.Errorf("Unsupport type '%T' in function calloc", n.Children()[2]) } goType, err := types.ResolveType(p, allocType) if err != nil { return nil, "", nil, nil, err } return &goast.CallExpr{ Fun: util.NewIdent("make"), Args: []goast.Expr{ &goast.ArrayType{Elt: goast.NewIdent(goType)}, size, }, }, allocType + " *", preStmts, postStmts, nil } // function "qsort" from stdlib.h if functionName == "qsort" && len(n.Children()) == 5 { defer func() { if err != nil { err = fmt.Errorf("Function: qsort. err = %v", err) } }() /* CallExpr 0x2c6b1b0 'void' |-ImplicitCastExpr 0x2c6b198 'void (*)(void *, size_t, size_t, __compar_fn_t)' | `-DeclRefExpr 0x2c6b070 'void (void *, size_t, size_t, __compar_fn_t)' Function 0x2bec110 'qsort' 'void (void *, size_t, size_t, __compar_fn_t)' |-ImplicitCastExpr 0x2c6b210 'void *' | `-ImplicitCastExpr 0x2c6b1f8 'int *' | `-DeclRefExpr 0x2c6b098 'int [6]' lvalue Var 0x2c6a6c0 'values' 'int [6]' |-ImplicitCastExpr 0x2c6b228 'size_t':'unsigned long' | `-IntegerLiteral 0x2c6b0c0 'int' 6 |-UnaryExprOrTypeTraitExpr 0x2c6b0f8 'unsigned long' sizeof 'int' `-ImplicitCastExpr 0x2c6b240 'int (*)(const void *, const void *)' `-DeclRefExpr 0x2c6b118 'int (const void *, const void *)' Function 0x2c6aa70 'compare' 'int (const void *, const void *)' */ var element [4]goast.Expr for i := 1; i < 5; i++ { el, _, newPre, newPost, err := transpileToExpr(n.Children()[i], p, false) if err != nil { return nil, "", nil, nil, err } element[i-1] = el preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) } // found the C type t := n.Children()[3].(*ast.UnaryExprOrTypeTraitExpr).Type2 t, err := types.ResolveType(p, t) if err != nil { return nil, "", nil, nil, err } var compareFunc string if v, ok := element[3].(*goast.Ident); ok { compareFunc = v.Name } else { return nil, "", nil, nil, fmt.Errorf("golang ast for compare function have type %T, expect ast.Ident", element[3]) } var varName string id := extractArray(element[0]) if id != nil { varName = id.Name } else { return nil, "", nil, nil, fmt.Errorf("cannot determine variable to be sorted") } p.AddImport("sort") src := fmt.Sprintf(`package main var %s func(a,b interface{})int var temp = func(i, j int) bool { c2goTempVarA := unsafe.Pointer(&%s[i]) c2goTempVarB := unsafe.Pointer(&%s[j]) return %s(c2goTempVarA, c2goTempVarB) <= 0 }`, compareFunc, varName, varName, compareFunc) // Create the AST by parsing src. fset := token.NewFileSet() // positions are relative to fset f, err := parser.ParseFile(fset, "", src, 0) if err != nil { return nil, "", nil, nil, err } // AST tree part of code after "var temp = ..." convertExpr := f.Decls[1].(*goast.GenDecl).Specs[0].(*goast.ValueSpec).Values[0] return &goast.CallExpr{ Fun: &goast.SelectorExpr{ X: goast.NewIdent("sort"), Sel: goast.NewIdent("SliceStable"), }, Args: []goast.Expr{ id, convertExpr, }, }, "", preStmts, postStmts, nil } // Get the function definition from it's name. The case where it is not // defined is handled below (we haven't seen the prototype yet). functionDef := p.GetFunctionDefinition(functionName) if functionDef == nil { // We do not have a prototype for the function, but we should not exit // here. Instead we will create a mock definition for it so that this // transpile function will always return something and continue. // // The mock function definition is never actually saved to the program // definitions, so each time we see the CallExpr it will run this every // time. This is so if we come across the real prototype later it will // be handled correctly. Or at least "more" correctly. functionDef = &program.FunctionDefinition{ Name: functionName, } if len(n.Children()) > 0 { if v, ok := n.Children()[0].(*ast.ImplicitCastExpr); ok && (types.IsFunction(v.Type) || types.IsTypedefFunction(p, v.Type)) { t := v.Type if v, ok := p.TypedefType[t]; ok { t = v } else { if types.IsTypedefFunction(p, t) { t = t[0 : len(t)-len(" *")] t, _ = p.TypedefType[t] } } fields, returns, err := types.ParseFunction(t) if err != nil { p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("Cannot resolve function : %v", err), n)) return nil, "", nil, nil, err } functionDef.ReturnType = returns[0] functionDef.ArgumentTypes = fields } } } else { // type correction for definition function in // package program var ok bool for pos, arg := range n.Children() { if pos == 0 { continue } if pos >= len(functionDef.ArgumentTypes) { continue } if arg, ok = arg.(*ast.ImplicitCastExpr); ok { arg.(*ast.ImplicitCastExpr).Type = functionDef.ArgumentTypes[pos-1] } } } if functionDef.Substitution != "" { parts := strings.Split(functionDef.Substitution, ".") importName := strings.Join(parts[:len(parts)-1], ".") p.AddImport(importName) parts2 := strings.Split(functionDef.Substitution, "/") functionName = parts2[len(parts2)-1] } args := []goast.Expr{} argTypes := []string{} i := 0 for _, arg := range n.Children()[1:] { e, eType, newPre, newPost, err := transpileToExpr(arg, p, false) if err != nil { return nil, "unknown2", nil, nil, err } argTypes = append(argTypes, eType) preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) _, arraySize := types.GetArrayTypeAndSize(eType) // If we are using varargs with Printf we need to make sure that certain // types are cast correctly. if functionName == "fmt.Printf" { // Make sure that any string parameters (const char*) are truncated // to the NULL byte. if arraySize != -1 { p.AddImport("github.com/elliotchance/c2go/noarch") e = util.NewCallExpr( "noarch.CStringToString", &goast.SliceExpr{X: e}, ) } // Byte slices (char*) must also be truncated to the NULL byte. // // TODO: This would also apply to other formatting functions like // fprintf, etc. if i > len(functionDef.ArgumentTypes)-1 && (eType == "char *" || eType == "char*") { p.AddImport("github.com/elliotchance/c2go/noarch") e = util.NewCallExpr("noarch.CStringToString", e) } } args = append(args, e) i++ } // These are the arguments once any transformations have taken place. realArgs := []goast.Expr{} // Apply transformation if needed. A transformation rearranges the return // value(s) and parameters. It is also used to indicate when a variable must // be passed by reference. if functionDef.ReturnParameters != nil || functionDef.Parameters != nil { for i, a := range functionDef.Parameters { byReference := false // Negative position means that it must be passed by reference. if a < 0 { byReference = true a = -a } // Rearrange the arguments. The -1 is because 0 would be the return // value. realArg := args[a-1] if byReference { // We have to create a temporary variable to pass by reference. // Then we can assign the real variable from it. realArg = &goast.UnaryExpr{ Op: token.AND, X: args[i], } } else { realArg, err = types.CastExpr(p, realArg, argTypes[i], functionDef.ArgumentTypes[i]) p.AddMessage( p.GenerateWarningOrErrorMessage(err, n, realArg == nil), ) if realArg == nil { realArg = util.NewNil() } } if realArg == nil { return nil, "", preStmts, postStmts, fmt.Errorf("Real argument is nil in function : %s", functionName) } realArgs = append(realArgs, realArg) } } else { // Keep all the arguments the same. But make sure we cast to the correct // types. for i, a := range args { if i > len(functionDef.ArgumentTypes)-1 { // This means the argument is one of the varargs so we don't // know what type it needs to be cast to. } else { a, err = types.CastExpr(p, a, argTypes[i], functionDef.ArgumentTypes[i]) if p.AddMessage(p.GenerateWarningMessage(err, n)) { a = util.NewNil() } } if a == nil { return nil, "", preStmts, postStmts, fmt.Errorf("Argument is nil in function : %s", functionName) } if len(functionDef.ArgumentTypes) > i { if !types.IsPointer(p, functionDef.ArgumentTypes[i]) { if strings.HasPrefix(functionDef.ArgumentTypes[i], "union ") { a = &goast.CallExpr{ Fun: &goast.SelectorExpr{ X: a, Sel: goast.NewIdent("copy"), }, Lparen: 1, } } } } realArgs = append(realArgs, a) } } // Added for support removing function `free` of // Example of C code: // free(i+=4,buffer) // Example of result Go code: // i += 4 // _ = buffer if functionDef.Substitution == "_" { devNull := &goast.AssignStmt{ Lhs: []goast.Expr{goast.NewIdent("_")}, Tok: token.ASSIGN, Rhs: []goast.Expr{realArgs[0]}, } preStmts = append(preStmts, devNull) return nil, "", preStmts, postStmts, nil } return util.NewCallExpr(functionName, realArgs...), functionDef.ReturnType, preStmts, postStmts, nil } func extractArray(expr goast.Expr) *goast.Ident { if v, ok := expr.(*goast.Ident); ok { return v } if se, ok := expr.(*goast.SliceExpr); ok { if v, ok2 := se.X.(*goast.Ident); ok2 { return v } } if ce, ok2 := expr.(*goast.CallExpr); ok2 && len(ce.Args) == 1 { if fid, ok3 := ce.Fun.(*goast.Ident); !ok3 || fid.Name != "unsafe.Pointer" { return nil } if ue, ok3 := ce.Args[0].(*goast.UnaryExpr); !ok3 || ue.Op != token.AND { return nil } else if idx, ok4 := ue.X.(*goast.IndexExpr); ok4 { if index, ok5 := idx.Index.(*goast.BasicLit); !ok5 || index.Value != "0" { return nil } if id, ok5 := idx.X.(*goast.Ident); ok5 { return id } } } return nil } c2go-0.26.10/transpiler/cast.go000066400000000000000000000111501410601753200161530ustar00rootroot00000000000000package transpiler import ( "fmt" goast "go/ast" "strings" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" "go/token" ) func transpileImplicitCastExpr(n *ast.ImplicitCastExpr, p *program.Program, exprIsStmt bool) ( expr goast.Expr, exprType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpileImplicitCastExpr. err = %v", err) } }() if n.Kind == ast.CStyleCastExprNullToPointer { expr = goast.NewIdent("nil") exprType = types.NullPointer return } if strings.Contains(n.Type, "enum") { if d, ok := n.Children()[0].(*ast.DeclRefExpr); ok { expr, exprType, err = util.NewIdent(d.Name), n.Type, nil return } } if isCastToUnsignedOfUnaryComplement(n, p) { return swapCastAndComplement(n, p, exprIsStmt) } expr, exprType, preStmts, postStmts, err = transpileToExpr(n.Children()[0], p, exprIsStmt) if err != nil { return nil, "", nil, nil, err } if exprType == types.NullPointer { expr = goast.NewIdent("nil") return } if len(n.Type) != 0 && len(n.Type2) != 0 && n.Type != n.Type2 { var tt string tt, err = types.ResolveType(p, n.Type) expr = &goast.CallExpr{ Fun: goast.NewIdent(tt), Lparen: 1, Args: []goast.Expr{expr}, } exprType = n.Type return } if !types.IsFunction(exprType) && !strings.ContainsAny(n.Type, "[]") { expr, err = types.CastExpr(p, expr, exprType, n.Type) if err != nil { return nil, "", nil, nil, err } exprType = n.Type } return } func isCastToUnsignedOfUnaryComplement(n *ast.ImplicitCastExpr, p *program.Program) (ret bool) { if !types.IsCInteger(p, n.Type) || !strings.Contains(n.Type, "unsigned ") { return } cn, ok := n.Children()[0].(*ast.UnaryOperator) if !ok || getTokenForOperator(cn.Operator) != token.XOR { return } return types.IsCInteger(p, cn.Type) && !strings.Contains(cn.Type, "unsigned ") } func swapCastAndComplement(n *ast.ImplicitCastExpr, p *program.Program, exprIsStmt bool) ( expr goast.Expr, exprType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { uo := n.Children()[0].(*ast.UnaryOperator) copyUnary := &ast.UnaryOperator{} copyImplicit := &ast.ImplicitCastExpr{} *copyUnary = *uo *copyImplicit = *n unaryChildren := uo.ChildNodes copyUnary.ChildNodes = []ast.Node{copyImplicit} copyUnary.Type = copyImplicit.Type copyImplicit.ChildNodes = unaryChildren return transpileToExpr(copyUnary, p, exprIsStmt) } func transpileCStyleCastExpr(n *ast.CStyleCastExpr, p *program.Program, exprIsStmt bool) ( expr goast.Expr, exprType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpileImplicitCastExpr. err = %v", err) } }() // Char overflow // example for byte(-1) // CStyleCastExpr 0x365f628 'char' // `-ParenExpr 0x365f608 'int' // `-ParenExpr 0x365f5a8 'int' // `-UnaryOperator 0x365f588 'int' prefix '-' // `-IntegerLiteral 0x365f568 'int' 1 if n.Type == "char" { if par, ok := n.Children()[0].(*ast.ParenExpr); ok { if par2, ok := par.Children()[0].(*ast.ParenExpr); ok { if u, ok := par2.Children()[0].(*ast.UnaryOperator); ok && u.IsPrefix { if _, ok := u.Children()[0].(*ast.IntegerLiteral); ok { return transpileToExpr(&ast.BinaryOperator{ Type: "int", Type2: "int", Operator: "+", ChildNodes: []ast.Node{ u, &ast.IntegerLiteral{ Type: "int", Value: "256", }, }, }, p, false) } } } } } if n.Kind == ast.CStyleCastExprNullToPointer { expr = goast.NewIdent("nil") exprType = types.NullPointer return } expr, exprType, preStmts, postStmts, err = transpileToExpr(n.Children()[0], p, exprIsStmt) if err != nil { return nil, "", nil, nil, err } if exprType == types.NullPointer { expr = goast.NewIdent("nil") return } if len(n.Type) != 0 && len(n.Type2) != 0 && n.Type != n.Type2 { var tt string tt, err = types.ResolveType(p, n.Type) expr = &goast.CallExpr{ Fun: goast.NewIdent(tt), Lparen: 1, Args: []goast.Expr{expr}, } exprType = n.Type return } if n.Kind == ast.CStyleCastExprToVoid { exprType = types.ToVoid return } if !types.IsFunction(exprType) && n.Kind != ast.ImplicitCastExprArrayToPointerDecay { expr, err = types.CastExpr(p, expr, exprType, n.Type) if err != nil { return nil, "", nil, nil, err } exprType = n.Type } return } c2go-0.26.10/transpiler/declarations.go000066400000000000000000000413661410601753200177050ustar00rootroot00000000000000// This file contains functions for transpiling declarations of variables and // types. The usage of variables is handled in variables.go. package transpiler import ( "errors" "fmt" goast "go/ast" "go/token" "strings" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" ) func newFunctionField(p *program.Program, name, cType string) (_ *goast.Field, err error) { if name == "" { err = fmt.Errorf("Name of function field cannot be empty") return } if !types.IsFunction(cType) { err = fmt.Errorf("Cannot create function field for type : %s", cType) return } field := &goast.Field{ Names: []*goast.Ident{ util.NewIdent(name), }, } var arg, ret []string arg, ret, err = types.SeparateFunction(p, cType) if err != nil { return } funcType := &goast.FuncType{} argFieldList := []*goast.Field{} for _, aa := range arg { argFieldList = append(argFieldList, &goast.Field{ Type: goast.NewIdent(aa), }) } funcType.Params = &goast.FieldList{ List: argFieldList, } funcType.Results = &goast.FieldList{ List: []*goast.Field{ &goast.Field{ Type: goast.NewIdent(ret[0]), }, }, } field.Type = funcType return field, nil } func transpileFieldDecl(p *program.Program, n *ast.FieldDecl) (field *goast.Field, err error) { if types.IsFunction(n.Type) { field, err = newFunctionField(p, n.Name, n.Type) if err == nil { return } } name := n.Name // FIXME: What causes this? See __darwin_fp_control for example. if name == "" { return nil, fmt.Errorf("Error : name of FieldDecl is empty") } // Add for fix bug in "stdlib.h" // build/tests/exit/main_test.go:90:11: undefined: wait // it is "union" with some anonymous struct if n.Type == "union wait *" { return nil, fmt.Errorf("Avoid struct `union wait *` in FieldDecl") } fieldType, err := types.ResolveType(p, n.Type) p.AddMessage(p.GenerateWarningMessage(err, n)) // TODO: The name of a variable or field cannot be a reserved word // https://github.com/elliotchance/c2go/issues/83 // Search for this issue in other areas of the codebase. if util.IsGoKeyword(name) { name += "_" } arrayType, arraySize := types.GetArrayTypeAndSize(n.Type) if arraySize != -1 { fieldType, err = types.ResolveType(p, arrayType) p.AddMessage(p.GenerateWarningMessage(err, n)) fieldType = fmt.Sprintf("[%d]%s", arraySize, fieldType) err = nil } return &goast.Field{ Names: []*goast.Ident{util.NewIdent(name)}, Type: util.NewTypeIdent(fieldType), }, nil } func transpileRecordDecl(p *program.Program, n *ast.RecordDecl) (decls []goast.Decl, err error) { name := n.Name if name == "" || p.IsTypeAlreadyDefined(name) { err = nil return } name = types.GenerateCorrectType(name) p.DefineType(name) // TODO: Some platform structs are ignored. // https://github.com/elliotchance/c2go/issues/85 if name == "__locale_struct" || name == "__sigaction" || name == "sigaction" { err = nil return } var fields []*goast.Field for pos := range n.Children() { switch field := n.Children()[pos].(type) { case *ast.FieldDecl: field.Type = types.GenerateCorrectType(field.Type) field.Type2 = types.GenerateCorrectType(field.Type2) f, err := transpileFieldDecl(p, field) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, field)) } else { fields = append(fields, f) } case *ast.RecordDecl: if field.Kind == "union" && pos+2 <= len(n.Children()) { if inField, ok := n.Children()[pos+1].(*ast.FieldDecl); ok { inField.Type = types.GenerateCorrectType(inField.Type) inField.Type2 = types.GenerateCorrectType(inField.Type2) field.Name = string(([]byte(inField.Type))[len("union "):]) declUnion, err := transpileRecordDecl(p, field) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, field)) } pos++ decls = append(decls, declUnion...) } } else if field.Kind == "struct" && pos+2 <= len(n.Children()) { if inField, ok := n.Children()[pos+1].(*ast.FieldDecl); ok { inField.Type = types.GenerateCorrectType(inField.Type) inField.Type2 = types.GenerateCorrectType(inField.Type2) field.Name = inField.Type if strings.HasPrefix(field.Name, "const ") { field.Name = field.Name[len("const "):] } if strings.HasPrefix(field.Name, "struct ") { field.Name = field.Name[len("struct "):] } if field.Name[len(field.Name)-1] == '*' { // star in struct field.Name = field.Name[:len(field.Name)-len(" *")] } if strings.Contains(field.Name, "[") { p.AddMessage(p.GenerateWarningMessage( fmt.Errorf("Not acceptable name of struct %s", field.Name), n)) continue } declStruct, err := transpileRecordDecl(p, field) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, field)) } pos++ decls = append(decls, declStruct...) } } else { decls, err = transpileRecordDecl(p, field) if err != nil { message := fmt.Sprintf("could not parse %v", field) p.AddMessage(p.GenerateWarningMessage(errors.New(message), field)) } } case *ast.FullComment: // We haven't Go ast struct for easy inject a comments. // All comments are added like CommentsGroup. // So, we can ignore that comment, because all comments // will be added by another way. default: message := fmt.Sprintf("could not parse %v", field) p.AddMessage(p.GenerateWarningMessage(errors.New(message), field)) } } s := program.NewStruct(n) if s.IsUnion { p.Unions["union "+s.Name] = s } else { p.Structs["struct "+s.Name] = s } if s.IsUnion { // Union size var size int size, err = types.SizeOf(p, "union "+name) // In normal case no error is returned, if err != nil { // but if we catch one, send it as a warning message := fmt.Sprintf("could not determine the size of type `union %s` for that reason: %s", name, err) p.AddMessage(p.GenerateWarningMessage(errors.New(message), n)) } else { // So, we got size, then // Add imports needed p.AddImports("unsafe") // Declaration for implementing union type d, err2 := transpileUnion(name, size, fields) if err2 != nil { return nil, err2 } decls = append(decls, d...) } return } decls = append(decls, &goast.GenDecl{ Tok: token.TYPE, Specs: []goast.Spec{ &goast.TypeSpec{ Name: util.NewIdent(name), Type: &goast.StructType{ Fields: &goast.FieldList{ List: fields, }, }, }, }, }) return } func transpileTypedefDecl(p *program.Program, n *ast.TypedefDecl) (decls []goast.Decl, err error) { // implicit code from clang at the head of each clang AST tree if n.IsImplicit && n.Pos.File == ast.PositionBuiltIn { return } defer func() { if err != nil { err = fmt.Errorf("Cannot transpile Typedef Decl : err = %v", err) } }() name := n.Name n.Type = types.CleanCType(n.Type) n.Type2 = types.CleanCType(n.Type2) if types.IsFunction(n.Type) { var field *goast.Field field, err = newFunctionField(p, n.Name, n.Type) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } else { // registration type p.TypedefType[n.Name] = n.Type decls = append(decls, &goast.GenDecl{ Tok: token.TYPE, Specs: []goast.Spec{ &goast.TypeSpec{ Name: util.NewIdent(name), Type: field.Type, }, }, }) err = nil return } } // added for support "typedef enum {...} dd" with empty name of struct // Result in Go: "type dd int32" if strings.Contains(n.Type, "enum") { // Registration new type in program.Program if !p.IsTypeAlreadyDefined(n.Name) { p.DefineType(n.Name) p.EnumTypedefName[n.Name] = true } decls = append(decls, &goast.GenDecl{ Tok: token.TYPE, Specs: []goast.Spec{ &goast.TypeSpec{ Name: util.NewIdent(name), Type: util.NewTypeIdent("int32"), }, }, }) err = nil return } if p.IsTypeAlreadyDefined(name) { err = nil return } p.DefineType(name) resolvedType, err := types.ResolveType(p, n.Type) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } // There is a case where the name of the type is also the definition, // like: // // type _RuneEntry _RuneEntry // // This of course is impossible and will cause the Go not to compile. // It itself is caused by lack of understanding (at this time) about // certain scenarios that types are defined as. The above example comes // from: // // typedef struct { // // ... some fields // } _RuneEntry; // // Until which time that we actually need this to work I am going to // suppress these. if name == resolvedType { err = nil return } if name == "__darwin_ct_rune_t" { resolvedType = p.ImportType("github.com/elliotchance/c2go/darwin.CtRuneT") } if name == "div_t" || name == "ldiv_t" || name == "lldiv_t" { intType := "int" if name == "ldiv_t" { intType = "long int" } else if name == "lldiv_t" { intType = "long long int" } // I don't know to extract the correct fields from the typedef to create // the internal definition. This is used in the noarch package // (stdio.go). // // The name of the struct is not prefixed with "struct " because it is a // typedef. p.Structs[name] = &program.Struct{ Name: name, IsUnion: false, Fields: map[string]interface{}{ "quot": intType, "rem": intType, }, } } err = nil if resolvedType == "" { resolvedType = "interface{}" } decls = append(decls, &goast.GenDecl{ Tok: token.TYPE, Specs: []goast.Spec{ &goast.TypeSpec{ Name: util.NewIdent(name), Type: util.NewTypeIdent(resolvedType), }, }, }) if v, ok := p.Structs["struct "+resolvedType]; ok { // Registration "typedef struct" with non-empty name of struct p.Structs["struct "+name] = v } else if v, ok := p.EnumConstantToEnum["enum "+resolvedType]; ok { // Registration "enum constants" p.EnumConstantToEnum["enum "+resolvedType] = v } else { // Registration "typedef type type2" p.TypedefType[n.Name] = n.Type } return } func transpileVarDecl(p *program.Program, n *ast.VarDecl) ( decls []goast.Decl, theType string, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpileVarDecl : err = %v", err) } }() // There may be some startup code for this global variable. if p.Function == nil { name := n.Name switch name { // Below are for macOS. case "__stdinp", "__stdoutp": theType = "*noarch.File" p.AddImport("github.com/elliotchance/c2go/noarch") p.AppendStartupExpr( util.NewBinaryExpr( goast.NewIdent(name), token.ASSIGN, util.NewTypeIdent("noarch."+util.Ucfirst(name[2:len(name)-1])), "*noarch.File", true, ), ) return []goast.Decl{&goast.GenDecl{ Tok: token.VAR, Specs: []goast.Spec{&goast.ValueSpec{ Names: []*goast.Ident{{Name: name}}, Type: util.NewTypeIdent(theType), Doc: p.GetMessageComments(), }}, }}, "", nil // Below are for linux. case "stdout", "stdin", "stderr": theType = "*noarch.File" p.AddImport("github.com/elliotchance/c2go/noarch") p.AppendStartupExpr( util.NewBinaryExpr( goast.NewIdent(name), token.ASSIGN, util.NewTypeIdent("noarch."+util.Ucfirst(name)), theType, true, ), ) return []goast.Decl{&goast.GenDecl{ Tok: token.VAR, Specs: []goast.Spec{&goast.ValueSpec{ Names: []*goast.Ident{{Name: name}}, Type: util.NewTypeIdent(theType), }}, Doc: p.GetMessageComments(), }}, "", nil default: // No init needed. } } // Ignore extern as there is no analogy for Go right now. if n.IsExtern && len(n.ChildNodes) == 0 { return } if strings.Contains(n.Type, "va_list") && strings.Contains(n.Type2, "va_list_tag") { // variable for va_list. see "variadic function" // header : // Example : // DeclStmt 0x2fd87e0 // `-VarDecl 0x2fd8780 col:10 used args 'va_list':'struct __va_list_tag [1]' // Result: // ... - convert to - c2goArgs ...interface{} // var args = c2goArgs return []goast.Decl{&goast.GenDecl{ Tok: token.VAR, Specs: []goast.Spec{ &goast.ValueSpec{ Names: []*goast.Ident{util.NewIdent("c2goVaList")}, Values: []goast.Expr{util.NewVaListTag()}, }, }, }}, "", nil } /* Example of DeclStmt for C code: void * a = NULL; void(*t)(void) = a; Example of AST: `-VarDecl 0x365fea8 col:9 used t 'void (*)(void)' cinit `-ImplicitCastExpr 0x365ff48 'void (*)(void)' `-ImplicitCastExpr 0x365ff30 'void *' `-DeclRefExpr 0x365ff08 'void *' lvalue Var 0x365f8c8 'r' 'void *' */ if len(n.Children()) > 0 { if v, ok := (n.Children()[0]).(*ast.ImplicitCastExpr); ok { if len(v.Type) > 0 { // Is it function ? if types.IsFunction(v.Type) { var fields, returns []string fields, returns, err = types.SeparateFunction(p, v.Type) if err != nil { err = fmt.Errorf("Cannot resolve function : %v", err) return } functionType := GenerateFuncType(fields, returns) nameVar1 := n.Name if vv, ok := v.Children()[0].(*ast.ImplicitCastExpr); ok { if decl, ok := vv.Children()[0].(*ast.DeclRefExpr); ok { nameVar2 := decl.Name return []goast.Decl{&goast.GenDecl{ Tok: token.VAR, Specs: []goast.Spec{&goast.ValueSpec{ Names: []*goast.Ident{{Name: nameVar1}}, Type: functionType, Values: []goast.Expr{&goast.TypeAssertExpr{ X: &goast.SelectorExpr{ X: util.NewCallExpr("*noarch.InterfaceWrapper", &goast.Ident{Name: nameVar2}), Sel: util.NewIdent("X"), }, Type: functionType, }}, Doc: p.GetMessageComments(), }, }}}, "", nil } } } } } } if types.IsFunction(n.Type) { var fields, returns []string fields, returns, err = types.SeparateFunction(p, n.Type) if err != nil { p.AddMessage(p.GenerateErrorMessage(fmt.Errorf("Cannot resolve function : %v", err), n)) err = nil // Error is ignored return } functionType := GenerateFuncType(fields, returns) nameVar1 := n.Name decls = append(decls, &goast.GenDecl{ Tok: token.VAR, Specs: []goast.Spec{&goast.ValueSpec{ Names: []*goast.Ident{{Name: nameVar1}}, Type: functionType, Doc: p.GetMessageComments(), }, }}) err = nil return } theType = n.Type _, isTypedefType := p.TypedefType[theType] theType, err = types.ResolveType(p, n.Type) if err != nil { p.AddMessage(p.GenerateErrorMessage(fmt.Errorf("Cannot resolve type %s : %v", theType, err), n)) err = nil // Error is ignored } p.GlobalVariables[n.Name] = theType name := n.Name preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} // TODO: Some platform structs are ignored. // https://github.com/elliotchance/c2go/issues/85 if name == "_LIB_VERSION" || name == "_IO_2_1_stdin_" || name == "_IO_2_1_stdout_" || name == "_IO_2_1_stderr_" || name == "_DefaultRuneLocale" || name == "_CurrentRuneLocale" { theType = "unknown10" return } defaultValue, _, newPre, newPost, err := getDefaultValueForVar(p, n) if err != nil { p.AddMessage(p.GenerateErrorMessage(err, n)) err = nil // Error is ignored } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) // Allocate slice so that it operates like a fixed size array. arrayType, arraySize := types.GetArrayTypeAndSize(n.Type) if arraySize != -1 && defaultValue == nil { if len(n.Children()) == 0 { var goArrayType string goArrayType, err = types.ResolveType(p, arrayType) if err != nil { p.AddMessage(p.GenerateErrorMessage(err, n)) err = nil // Error is ignored } defaultValue = []goast.Expr{ util.NewCallExpr( "make", &goast.ArrayType{ Elt: util.NewTypeIdent(goArrayType), }, util.NewIntLit(arraySize), util.NewIntLit(arraySize), ), } } else { if iniList, ok := n.Children()[0].(*ast.InitListExpr); ok { var list goast.Expr list, _, err = transpileInitListExpr(iniList, p) if err != nil { p.AddMessage(p.GenerateErrorMessage(err, n)) err = nil // Error is ignored } else { defaultValue = []goast.Expr{list} } } } } if len(preStmts) != 0 || len(postStmts) != 0 { p.AddMessage(p.GenerateErrorMessage(fmt.Errorf("Not acceptable length of Stmt : pre(%d), post(%d)", len(preStmts), len(postStmts)), n)) } var typeResult goast.Expr if isTypedefType { typeResult = goast.NewIdent(theType) } else { typeResult = util.NewTypeIdent(theType) } return []goast.Decl{&goast.GenDecl{ Tok: token.VAR, Specs: []goast.Spec{ &goast.ValueSpec{ Names: []*goast.Ident{util.NewIdent(n.Name)}, Type: typeResult, Values: defaultValue, Doc: p.GetMessageComments(), }, }, }}, "", nil } c2go-0.26.10/transpiler/enum.go000066400000000000000000000203021410601753200161640ustar00rootroot00000000000000// This file contains transpiling for enums. package transpiler import ( "fmt" "go/token" "strconv" goast "go/ast" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" ) // ctypeEnumValue generates a specific expression for values used by some // constants in ctype.h. This is to get around an issue that the real values // need to be evaluated by the compiler; which c2go does not yet do. // // TODO: Ability to evaluate constant expressions at compile time // https://github.com/elliotchance/c2go/issues/77 func ctypeEnumValue(value int, t token.Token) goast.Expr { // Produces an expression like: ((1 << (0)) << 8) return &goast.ParenExpr{ X: util.NewBinaryExpr( &goast.ParenExpr{ X: util.NewBinaryExpr( util.NewIntLit(1), token.SHL, util.NewIntLit(value), "int", false, ), }, t, util.NewIntLit(8), "int", false, ), } } func transpileEnumConstantDecl(p *program.Program, n *ast.EnumConstantDecl) ( *goast.ValueSpec, []goast.Stmt, []goast.Stmt) { var value goast.Expr = util.NewIdent("iota") valueType := "int32" preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} // Special cases for linux ctype.h. See the description for the // ctypeEnumValue() function. switch n.Name { case "_ISupper": value = ctypeEnumValue(0, token.SHL) // "((1 << (0)) << 8)" valueType = "uint16" case "_ISlower": value = ctypeEnumValue(1, token.SHL) // "((1 << (1)) << 8)" valueType = "uint16" case "_ISalpha": value = ctypeEnumValue(2, token.SHL) // "((1 << (2)) << 8)" valueType = "uint16" case "_ISdigit": value = ctypeEnumValue(3, token.SHL) // "((1 << (3)) << 8)" valueType = "uint16" case "_ISxdigit": value = ctypeEnumValue(4, token.SHL) // "((1 << (4)) << 8)" valueType = "uint16" case "_ISspace": value = ctypeEnumValue(5, token.SHL) // "((1 << (5)) << 8)" valueType = "uint16" case "_ISprint": value = ctypeEnumValue(6, token.SHL) // "((1 << (6)) << 8)" valueType = "uint16" case "_ISgraph": value = ctypeEnumValue(7, token.SHL) // "((1 << (7)) << 8)" valueType = "uint16" case "_ISblank": value = ctypeEnumValue(8, token.SHR) // "((1 << (8)) >> 8)" valueType = "uint16" case "_IScntrl": value = ctypeEnumValue(9, token.SHR) // "((1 << (9)) >> 8)" valueType = "uint16" case "_ISpunct": value = ctypeEnumValue(10, token.SHR) // "((1 << (10)) >> 8)" valueType = "uint16" case "_ISalnum": value = ctypeEnumValue(11, token.SHR) // "((1 << (11)) >> 8)" valueType = "uint16" default: if len(n.Children()) > 0 { var err error value, _, preStmts, postStmts, err = transpileToExpr(n.Children()[0], p, false) if err != nil { panic(err) } } } return &goast.ValueSpec{ Names: []*goast.Ident{util.NewIdent(n.Name)}, Type: util.NewTypeIdent(valueType), Values: []goast.Expr{value}, Doc: p.GetMessageComments(), }, preStmts, postStmts } func transpileEnumDecl(p *program.Program, n *ast.EnumDecl) (decls []goast.Decl, err error) { preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} // For case `enum` without name if n.Name == "" { // create all EnumConstant like just constants var counter int for _, child := range n.Children() { if c, ok := child.(*ast.EnumConstantDecl); ok { var ( e goast.Spec newPre []goast.Stmt newPost []goast.Stmt val *goast.ValueSpec ) val, newPre, newPost = transpileEnumConstantDecl(p, c) if len(newPre) > 0 || len(newPost) > 0 { p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("Check - added in code : (%d)(%d)", len(newPre), len(newPost)), n)) } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) parseEnumBasicLit := func(b *goast.BasicLit) (_ goast.Spec, counter int, err error) { value, err := strconv.Atoi(b.Value) if err != nil { err = fmt.Errorf("Cannot parse '%s' in BasicLit", b.Value) return } return &goast.ValueSpec{ Names: []*goast.Ident{{Name: c.Name}}, Values: []goast.Expr{&goast.BasicLit{Kind: token.INT, Value: b.Value}}, Type: val.Type, Doc: p.GetMessageComments(), }, value, nil } switch v := val.Values[0].(type) { case *goast.Ident: e = &goast.ValueSpec{ Names: []*goast.Ident{{Name: c.Name}}, Values: []goast.Expr{&goast.BasicLit{Kind: token.INT, Value: strconv.Itoa(counter)}}, Type: val.Type, Doc: p.GetMessageComments(), } counter++ case *goast.BasicLit: var value int e, value, err = parseEnumBasicLit(v) if err != nil { e = val counter++ p.AddMessage(p.GenerateWarningMessage( fmt.Errorf("Cannot parse '%s' in BasicLit", v.Value), n)) break } counter = value counter++ case *goast.CallExpr: e = val if id, ok := v.Fun.(*goast.Ident); !ok || len(v.Args) != 1 || !types.IsGoIntegerType(id.Name) { p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("Add support of continues counter for type : *goast.CallExpr != integer cast"), n)) break } if lit, ok := v.Args[0].(*goast.BasicLit); ok { var value int e, value, err = parseEnumBasicLit(lit) if err != nil { e = val counter++ p.AddMessage(p.GenerateWarningMessage( fmt.Errorf("Cannot parse '%s' in BasicLit", lit.Value), n)) break } counter = value counter++ } else { p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("Add support of continues counter for type : *goast.CallExpr (integer cast) with argument type : %T", v), n)) } default: e = val p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("Add support of continues counter for type : %T", v), n)) } decls = append(decls, &goast.GenDecl{ Tok: token.CONST, Specs: []goast.Spec{ e, }, }) } } err = nil return } // For case `enum` with name theType, err := types.ResolveType(p, "int") if err != nil { // by defaults enum in C is INT p.AddMessage(p.GenerateWarningMessage(err, n)) } // Create alias of enum for int decls = append(decls, &goast.GenDecl{ Tok: token.TYPE, Specs: []goast.Spec{ &goast.TypeSpec{ Name: &goast.Ident{ Name: n.Name, Obj: goast.NewObj(goast.Typ, n.Name), }, Type: util.NewTypeIdent(theType), }, }, }) // Registration new type in program.Program if !p.IsTypeAlreadyDefined(n.Name) { p.DefineType(n.Name) } baseType := util.NewTypeIdent(n.Name) decl := &goast.GenDecl{ Tok: token.CONST, } // counter for replace iota var counter int var i int for _, c := range n.Children() { if _, ok := c.(*ast.EnumConstantDecl); !ok { // add for avoid comments elements continue } e, newPre, newPost := transpileEnumConstantDecl(p, c.(*ast.EnumConstantDecl)) preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) e.Names[0].Obj = goast.NewObj(goast.Con, e.Names[0].Name) if i > 0 { e.Type = nil e.Values = nil } if i == 0 { e.Type = baseType if t, ok := e.Type.(*goast.Ident); ok { t.Obj = &goast.Object{ Name: n.Name, Kind: goast.Typ, Decl: &goast.TypeSpec{ Name: &goast.Ident{ Name: n.Name, }, Type: &goast.Ident{ Name: "int", // enum in C is "INT" by default }, }, } } } if len(c.(*ast.EnumConstantDecl).ChildNodes) > 0 { if integr, ok := c.(*ast.EnumConstantDecl).ChildNodes[0].(*ast.IntegerLiteral); ok { is, err := strconv.ParseInt(integr.Value, 10, 64) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } counter = int(is) } } // Insert value of constants e.Values = []goast.Expr{ &goast.BasicLit{ Kind: token.INT, Value: strconv.Itoa(counter), }, } // Position inside (....), it is // not value of constants e.Names[0].Obj.Data = i counter++ decl.Specs = append(decl.Specs, e) // registration of enum constants p.EnumConstantToEnum[e.Names[0].Name] = "enum " + n.Name // calculate next position without comments i++ } // important value for creating (.....) // with constants inside decl.Lparen = 1 decl.Rparen = 2 decls = append(decls, decl) err = nil return } c2go-0.26.10/transpiler/functions.go000066400000000000000000000273731410601753200172470ustar00rootroot00000000000000// This file contains functions for declaring function prototypes, expressions // that call functions, returning from function and the coordination of // processing the function bodies. package transpiler import ( "fmt" "strings" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" goast "go/ast" "go/token" ) // getFunctionBody returns the function body as a CompoundStmt. If the function // is a prototype or forward declaration (meaning it has no body) then nil is // returned. func getFunctionBody(n *ast.FunctionDecl) *ast.CompoundStmt { // It's possible that the last node is the CompoundStmt (after all the // parameter declarations) - but I don't know this for certain so we will // look at all the children for now. for _, c := range n.Children() { if b, ok := c.(*ast.CompoundStmt); ok { return b } } return nil } // transpileFunctionDecl transpiles the function prototype. // // The function prototype may also have a body. If it does have a body the whole // function will be transpiled into Go. // // If there is no function body we register the function interally (actually // either way the function is registered internally) but we do not do anything // because Go does not use or have any use for forward declarations of // functions. func transpileFunctionDecl(n *ast.FunctionDecl, p *program.Program) ( decls []goast.Decl, err error) { var body *goast.BlockStmt // This is set at the start of the function declaration so when the // ReturnStmt comes alone it will know what the current function is, and // therefore be able to lookup what the real return type should be. I'm sure // there is a much better way of doing this. p.Function = n defer func() { // Reset the function name when we go out of scope. p.Function = nil }() n.Name = util.ConvertFunctionNameFromCtoGo(n.Name) // Always register the new function. Only from this point onwards will // we be allowed to refer to the function. if p.GetFunctionDefinition(n.Name) == nil { p.AddFunctionDefinition(program.FunctionDefinition{ Name: n.Name, ReturnType: getFunctionReturnType(n.Type), ArgumentTypes: getFunctionArgumentTypes(n), Substitution: "", }) } // If the function has a direct substitute in Go we do not want to // output the C definition of it. f := p.GetFunctionDefinition(n.Name) if f != nil && f.Substitution != "" { err = nil return } // Test if the function has a body. This is identified by a child node that // is a CompoundStmt (since it is not valid to have a function body without // curly brackets). functionBody := getFunctionBody(n) if functionBody != nil { var pre, post []goast.Stmt body, pre, post, err = transpileToBlockStmt(functionBody, p) if err != nil || len(pre) > 0 || len(post) > 0 { p.AddMessage(p.GenerateErrorMessage(fmt.Errorf("Not correct result in function %s body: err = %v", n.Name, err), n)) err = nil // Error is ignored } } // These functions cause us trouble for whatever reason. Some of them might // even work now. // // TODO: Some functions are ignored because they are too much trouble // https://github.com/elliotchance/c2go/issues/78 if n.Name == "__istype" || n.Name == "__isctype" || n.Name == "__wcwidth" || n.Name == "__sputc" || n.Name == "__inline_signbitf" || n.Name == "__inline_signbitd" || n.Name == "__inline_signbitl" { err = nil return } if functionBody != nil { // If verbose mode is on we print the name of the function as a comment // immediately to stdout. This will appear at the top of the program but // make it much easier to diagnose when the transpiler errors. if p.Verbose { fmt.Printf("// Function: %s(%s)\n", f.Name, strings.Join(f.ArgumentTypes, ", ")) } var fieldList = &goast.FieldList{} fieldList, err = getFieldList(n, p) if err != nil { return } t, err := types.ResolveType(p, f.ReturnType) p.AddMessage(p.GenerateWarningMessage(err, n)) if p.Function != nil && p.Function.Name == "main" { // main() function does not have a return type. t = "" // This collects statements that will be placed at the top of // (before any other code) in main(). prependStmtsInMain := []goast.Stmt{} // In Go, the main() function does not take the system arguments. // Instead they are accessed through the os package. We create new // variables in the main() function (if needed), immediately after // the __init() for these variables. if len(fieldList.List) > 0 { p.AddImport("os") prependStmtsInMain = append( prependStmtsInMain, &goast.AssignStmt{ Lhs: []goast.Expr{fieldList.List[0].Names[0]}, Tok: token.DEFINE, Rhs: []goast.Expr{util.NewCallExpr("int32", util.NewCallExpr("len", util.NewTypeIdent("os.Args")))}, }, ) } if len(fieldList.List) > 1 { argvMultiArrayName := &goast.Ident{} argvArrayName := &goast.Ident{} *argvArrayName = *fieldList.List[1].Names[0] *argvMultiArrayName = *argvArrayName argvArrayName.Name += "__array" argvMultiArrayName.Name += "__multiarray" prependStmtsInMain = append( prependStmtsInMain, &goast.AssignStmt{ Lhs: []goast.Expr{argvMultiArrayName}, Tok: token.DEFINE, Rhs: []goast.Expr{&goast.CompositeLit{Type: util.NewTypeIdent("[][]byte")}}, }, &goast.AssignStmt{ Lhs: []goast.Expr{argvArrayName}, Tok: token.DEFINE, Rhs: []goast.Expr{&goast.CompositeLit{Type: util.NewTypeIdent("[]*byte")}}, }, &goast.RangeStmt{ Key: goast.NewIdent("_"), Value: util.NewIdent("argvSingle"), Tok: token.DEFINE, X: util.NewTypeIdent("os.Args"), Body: &goast.BlockStmt{ List: []goast.Stmt{ &goast.AssignStmt{ Lhs: []goast.Expr{argvMultiArrayName}, Tok: token.ASSIGN, Rhs: []goast.Expr{util.NewCallExpr( "append", argvMultiArrayName, util.NewCallExpr("append", util.NewCallExpr("[]byte", util.NewIdent("argvSingle")), util.NewIntLit(0)), )}, }, }, }, }, &goast.RangeStmt{ Key: goast.NewIdent("_"), Value: util.NewIdent("argvSingle"), Tok: token.DEFINE, X: argvMultiArrayName, Body: &goast.BlockStmt{ List: []goast.Stmt{ &goast.AssignStmt{ Lhs: []goast.Expr{argvArrayName}, Tok: token.ASSIGN, Rhs: []goast.Expr{util.NewCallExpr( "append", argvArrayName, &goast.UnaryExpr{ Op: token.AND, X: &goast.IndexExpr{ X: util.NewIdent("argvSingle"), Index: util.NewIntLit(0), }, }, )}, }, }, }, }, &goast.AssignStmt{ Lhs: []goast.Expr{fieldList.List[1].Names[0]}, Tok: token.DEFINE, Rhs: []goast.Expr{ &goast.StarExpr{ X: &goast.CallExpr{ Fun: &goast.ParenExpr{ X: util.NewTypeIdent("***byte"), }, Args: []goast.Expr{ util.NewCallExpr("unsafe.Pointer", &goast.UnaryExpr{ Op: token.AND, X: argvArrayName, }), }, }, }, }, }) } // Prepend statements for main(). body.List = append(prependStmtsInMain, body.List...) // The main() function does not have arguments or a return value. fieldList = &goast.FieldList{} } // Each function MUST have "ReturnStmt", // except function without return type var addReturnName bool if len(body.List) > 0 { last := body.List[len(body.List)-1] if _, ok := last.(*goast.ReturnStmt); !ok && t != "" { body.List = append(body.List, &goast.ReturnStmt{}) addReturnName = true } } decls = append(decls, &goast.FuncDecl{ Name: util.NewIdent(n.Name), Type: util.NewFuncType(fieldList, t, addReturnName), Body: body, }) } err = nil return } // getFieldList returns the parameters of a C function as a Go AST FieldList. func getFieldList(f *ast.FunctionDecl, p *program.Program) (_ *goast.FieldList, err error) { defer func() { if err != nil { err = fmt.Errorf("Error in function field list. err = %v", err) } }() r := []*goast.Field{} for _, n := range f.Children() { if v, ok := n.(*ast.ParmVarDecl); ok { if types.IsFunction(v.Type) { field, err := newFunctionField(p, v.Name, v.Type) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, v)) continue } r = append(r, field) continue } // when passing va_list to a function, always name it c2goVaList if v.Type == "struct __va_list_tag *" { v.Name = "c2goVaList" } t, err := types.ResolveType(p, v.Type) p.AddMessage(p.GenerateWarningMessage(err, f)) r = append(r, &goast.Field{ Names: []*goast.Ident{util.NewIdent(v.Name)}, Type: util.NewTypeIdent(t), }) } } // for function argument: ... if strings.Contains(f.Type, "...") { r = append(r, &goast.Field{ Names: []*goast.Ident{util.NewIdent("c2goArgs")}, Type: &goast.Ellipsis{ Ellipsis: 1, Elt: &goast.InterfaceType{ Interface: 1, Methods: &goast.FieldList{ Opening: 1, }, Incomplete: false, }, }, }) } return &goast.FieldList{ List: r, }, nil } func transpileReturnStmt(n *ast.ReturnStmt, p *program.Program) ( _ goast.Stmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpileReturnStmt. err = %v", err) } }() // There may not be a return value. Then we don't have to both ourselves // with all the rest of the logic below. if len(n.Children()) == 0 { return &goast.ReturnStmt{}, nil, nil, nil } var eType string var e goast.Expr e, eType, preStmts, postStmts, err = transpileToExpr(n.Children()[0], p, false) if err != nil { return nil, nil, nil, err } if e == nil { return nil, nil, nil, fmt.Errorf("Expr is nil") } f := p.GetFunctionDefinition(p.Function.Name) t, err := types.CastExpr(p, e, eType, f.ReturnType) if p.AddMessage(p.GenerateWarningMessage(err, n)) { t = util.NewNil() } results := []goast.Expr{t} // main() function is not allowed to return a result. Use os.Exit if // non-zero. if p.Function != nil && p.Function.Name == "main" { litExpr, isLiteral := getReturnLiteral(e) if !isLiteral || (isLiteral && litExpr.Value != "0") { p.AddImport("os") return util.NewExprStmt(util.NewCallExpr("os.Exit", util.NewCallExpr("int", results...))), preStmts, postStmts, nil } results = []goast.Expr{} } return &goast.ReturnStmt{ Results: results, }, preStmts, postStmts, nil } func getReturnLiteral(e goast.Expr) (litExpr *goast.BasicLit, ok bool) { if litExpr, ok = e.(*goast.BasicLit); ok { return } if callExpr, ok2 := e.(*goast.CallExpr); ok2 { if funExpr, ok3 := callExpr.Fun.(*goast.Ident); !ok3 || funExpr.Name != "int32" { return nil, false } if len(callExpr.Args) != 1 { return nil, false } if litExpr, ok = callExpr.Args[0].(*goast.BasicLit); ok { return } } return nil, false } func getFunctionReturnType(f string) string { // The C type of the function will be the complete prototype, like: // // __inline_isfinitef(float) int // // will have a C type of: // // int (float) // // The arguments will handle themselves, we only care about the return type // ('int' in this case) returnType := strings.TrimSpace(strings.Split(f, "(")[0]) if returnType == "" { panic(fmt.Sprintf("unable to extract the return type from: %s", f)) } return returnType } // getFunctionArgumentTypes returns the C types of the arguments in a function. func getFunctionArgumentTypes(f *ast.FunctionDecl) []string { r := []string{} for _, n := range f.Children() { if v, ok := n.(*ast.ParmVarDecl); ok { r = append(r, v.Type) } } return r } c2go-0.26.10/transpiler/goto.go000066400000000000000000000016231410601753200161750ustar00rootroot00000000000000// This file contains functions for transpiling goto/label statements. package transpiler import ( goast "go/ast" "go/token" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/util" ) func transpileLabelStmt(n *ast.LabelStmt, p *program.Program) (*goast.LabeledStmt, []goast.Stmt, []goast.Stmt, error) { var post []goast.Stmt for _, node := range n.Children() { var stmt goast.Stmt stmt, preStmts, postStmts, err := transpileToStmt(node, p) if err != nil { return nil, nil, nil, err } post = combineStmts(stmt, preStmts, postStmts) } return &goast.LabeledStmt{ Label: util.NewIdent(n.Name), Stmt: &goast.EmptyStmt{}, }, []goast.Stmt{}, post, nil } func transpileGotoStmt(n *ast.GotoStmt, p *program.Program) (*goast.BranchStmt, error) { return &goast.BranchStmt{ Label: util.NewIdent(n.Name), Tok: token.GOTO, }, nil } c2go-0.26.10/transpiler/literals.go000066400000000000000000000057241410601753200170520ustar00rootroot00000000000000// This file contains transpiling functions for literals and constants. Literals // are single values like 123 or "hello". package transpiler import ( "bytes" "fmt" "go/token" goast "go/ast" "strconv" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" ) func transpileFloatingLiteral(n *ast.FloatingLiteral) *goast.BasicLit { return util.NewFloatLit(n.Value) } func transpileStringLiteral(n *ast.StringLiteral) goast.Expr { // Example: // StringLiteral 0x280b918 'char [30]' lvalue "%0" s, err := types.GetAmountArraySize(n.Type) if err != nil { return toBytePointer(util.NewCallExpr("[]byte", util.NewStringLit(strconv.Quote(n.Value+"\x00")))) } buf := bytes.NewBufferString(n.Value + "\x00") if buf.Len() < s { buf.Write(make([]byte, s-buf.Len())) } return toBytePointer(util.NewCallExpr("[]byte", util.NewStringLit(strconv.Quote(buf.String())))) } func toBytePointer(expr goast.Expr) goast.Expr { return &goast.ParenExpr{ X: &goast.UnaryExpr{ Op: token.AND, X: &goast.IndexExpr{ X: expr, Index: util.NewIntLit(0), }, }, } } func transpileIntegerLiteral(n *ast.IntegerLiteral) (ret goast.Expr) { ret = &goast.BasicLit{ Kind: token.INT, Value: n.Value, } if n.Type == "int" { ret = util.NewCallExpr("int32", ret) } return } func transpileCharacterLiteral(n *ast.CharacterLiteral) *goast.BasicLit { return &goast.BasicLit{ Kind: token.CHAR, Value: fmt.Sprintf("%q", n.Value), } } func transpilePredefinedExpr(n *ast.PredefinedExpr, p *program.Program) (goast.Expr, string, error) { // A predefined expression is a literal that is not given a value until // compile time. // // TODO: Predefined expressions are not evaluated // https://github.com/elliotchance/c2go/issues/81 var e goast.Expr switch n.Name { case "__PRETTY_FUNCTION__": e = util.NewCallExpr( "[]byte", util.NewStringLit(`"void print_number(int *)\x00"`), ) case "__func__": e = util.NewCallExpr( "[]byte", util.NewStringLit(strconv.Quote(p.Function.Name+"\x00")), ) default: // There are many more. panic(fmt.Sprintf("unknown PredefinedExpr: %s", n.Name)) } e = &goast.ParenExpr{ X: &goast.UnaryExpr{ Op: token.AND, X: &goast.IndexExpr{ X: e, Index: util.NewIntLit(0), }, }, } return e, "const char*", nil } func transpileCompoundLiteralExpr(n *ast.CompoundLiteralExpr, p *program.Program) (goast.Expr, string, error) { expr, t, _, _, err := transpileToExpr(n.Children()[0], p, false) return expr, t, err } func transpileConstantExpr(n *ast.ConstantExpr, p *program.Program) (goast.Expr, string, error) { children := n.Children() expr, t, _, _, err := transpileToExpr(children[0], p, false) if len(children) != 1 { p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("ConstantExpr has %d children, expected 1 child", len(children)), n)) } if len(n.Type) > 0 { t = n.Type } return expr, t, err } c2go-0.26.10/transpiler/literals_test.go000066400000000000000000000020531410601753200201010ustar00rootroot00000000000000package transpiler import ( "reflect" "testing" "unicode/utf8" "github.com/elliotchance/c2go/ast" goast "go/ast" "go/token" ) var chartests = []struct { in int // Integer Character Code out string // Output Character Literal }{ // NUL byte {0, "'\\x00'"}, // ASCII control characters {7, "'\\a'"}, {8, "'\\b'"}, {9, "'\\t'"}, {10, "'\\n'"}, {11, "'\\v'"}, {12, "'\\f'"}, {13, "'\\r'"}, // printable ASCII {32, "' '"}, {34, "'\"'"}, {39, "'\\''"}, {65, "'A'"}, {92, "'\\\\'"}, {191, "'¿'"}, // printable unicode {948, "'δ'"}, {0x03a9, "'Ω'"}, {0x2020, "'†'"}, // non-printable unicode {0xffff, "'\\uffff'"}, {utf8.MaxRune, "'\\U0010ffff'"}, } func TestCharacterLiterals(t *testing.T) { for _, tt := range chartests { expected := &goast.BasicLit{Kind: token.CHAR, Value: tt.out} actual := transpileCharacterLiteral(&ast.CharacterLiteral{Value: tt.in}) if !reflect.DeepEqual(expected, actual) { t.Errorf("input: %v", tt.in) t.Errorf(" expected: %v", expected) t.Errorf(" actual: %v", actual) } } } c2go-0.26.10/transpiler/operators.go000066400000000000000000000651031410601753200172460ustar00rootroot00000000000000// This file contains functions transpiling some general operator expressions. // See binary.go and unary.go. package transpiler import ( "bytes" "fmt" "go/parser" "go/printer" "go/token" "html/template" "strings" goast "go/ast" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" ) // transpileConditionalOperator transpiles a conditional (also known as a // ternary) operator: // // a ? b : c // // We cannot simply convert these to an "if" statement because they by inside // another expression. // // Since Go does not support the ternary operator or inline "if" statements we // use a closure to work the same way. // // It is also important to note that C only evaulates the "b" or "c" condition // based on the result of "a" (from the above example). func transpileConditionalOperator(n *ast.ConditionalOperator, p *program.Program) ( _ *goast.CallExpr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpile ConditionalOperator : err = %v", err) } }() // a - condition a, aType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false) if err != nil { return } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) // null in C is zero if aType == types.NullPointer { a = &goast.BasicLit{ Kind: token.INT, Value: "0", } aType = "int" } a, err = types.CastExpr(p, a, aType, "bool") if err != nil { return } // b - body b, bType, newPre, newPost, err := transpileToExpr(n.Children()[1], p, false) if err != nil { return } // Theoretically, length is must be zero if len(newPre) > 0 || len(newPost) > 0 { p.AddMessage(p.GenerateWarningMessage( fmt.Errorf("length of pre or post in body must be zero. {%d,%d}", len(newPre), len(newPost)), n)) } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) if n.Type != "void" { b, err = types.CastExpr(p, b, bType, n.Type) if err != nil { return } bType = n.Type } // c - else body c, cType, newPre, newPost, err := transpileToExpr(n.Children()[2], p, false) if err != nil { return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) if n.Type != "void" { c, err = types.CastExpr(p, c, cType, n.Type) if err != nil { return } cType = n.Type } // rightType - generate return type var returnType string if n.Type != "void" { returnType, err = types.ResolveType(p, n.Type) if err != nil { return } } var bod, els goast.BlockStmt bod.Lbrace = 1 if bType != types.ToVoid { if n.Type != "void" { bod.List = []goast.Stmt{ &goast.ReturnStmt{ Results: []goast.Expr{b}, }, } } else { bod.List = []goast.Stmt{&goast.ExprStmt{b}} } } els.Lbrace = 1 if cType != types.ToVoid { if n.Type != "void" { els.List = []goast.Stmt{ &goast.ReturnStmt{ Results: []goast.Expr{c}, }, } } else { els.List = []goast.Stmt{&goast.ExprStmt{c}} } } return util.NewFuncClosure( returnType, &goast.IfStmt{ Cond: a, Body: &bod, Else: &els, }, ), n.Type, preStmts, postStmts, nil } // transpileParenExpr transpiles an expression that is wrapped in parentheses. // There is a special case where "(0)" is treated as a NULL (since that's what // the macro expands to). We have to return the type as "null" since we don't // know at this point what the NULL expression will be used in conjunction with. func transpileParenExpr(n *ast.ParenExpr, p *program.Program) ( r *goast.ParenExpr, exprType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpile ParenExpr. err = %v", err) p.AddMessage(p.GenerateWarningMessage(err, n)) } }() expr, exprType, preStmts, postStmts, err := transpileToExpr(n.Children()[0], p, false) if err != nil { return } if expr == nil { err = fmt.Errorf("Expr is nil") return } if exprType == types.NullPointer { r = &goast.ParenExpr{X: expr} return } if !types.IsFunction(exprType) && exprType != "void" && exprType != types.ToVoid { expr, err = types.CastExpr(p, expr, exprType, n.Type) if err != nil { return } exprType = n.Type } r = &goast.ParenExpr{X: expr} return } // pointerArithmetic - operations between 'int' and pointer // Example C code : ptr += i // ptr = ((*int)(unsafe.Pointer(uintptr(unsafe.Pointer(ptr)) + (i)*unsafe.Sizeof(*ptr)))) // , where i - left // '+' - operator // 'ptr' - right // 'int' - leftType transpiled in Go type // Note: // 1) rigthType MUST be 'int' // 2) pointerArithmetic - implemented ONLY right part of formula // 3) right is MUST be positive value, because impossible multiply uintptr to (-1) func pointerArithmetic(p *program.Program, left goast.Expr, leftType string, right goast.Expr, rightType string, operator token.Token) ( _ goast.Expr, _ string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpile pointerArithmetic. err = %v", err) } }() right, err = types.CastExpr(p, right, rightType, "int") if err != nil { return } if !types.IsPointer(p, leftType) { err = fmt.Errorf("left type is not a pointer : '%s'", leftType) return } resolvedLeftType, err := types.ResolveType(p, leftType) if err != nil { return } type pA struct { Name string // name of variable: 'ptr' Type string // type of variable: 'int','double' Condition string // condition : '-1' ,'(-1+2-2)' Operator string // operator : '+', '-' } var s pA { var buf bytes.Buffer _ = printer.Fprint(&buf, token.NewFileSet(), left) s.Name = buf.String() } { var buf bytes.Buffer _ = printer.Fprint(&buf, token.NewFileSet(), right) s.Condition = buf.String() } s.Type = resolvedLeftType s.Operator = "+" if operator == token.SUB { s.Operator = "-" } var src string if util.IsAddressable(left) { src = `package main func main(){ a := (({{ .Type }})(unsafe.Pointer(uintptr(unsafe.Pointer({{ .Name }})) {{ .Operator }} (uintptr)({{ .Condition }})*unsafe.Sizeof(*{{ .Name }})))) }` } else { src = `package main func main(){ a := (({{ .Type }})(func()unsafe.Pointer{ tempVar := {{ .Name }} return unsafe.Pointer(uintptr(unsafe.Pointer(tempVar)) {{ .Operator }} (uintptr)({{ .Condition }})*unsafe.Sizeof(*tempVar)) }())) }` } tmpl := template.Must(template.New("").Parse(src)) var source bytes.Buffer err = tmpl.Execute(&source, s) if err != nil { err = fmt.Errorf("Cannot execute template. err = %v", err) return } // Create the AST by parsing src. fset := token.NewFileSet() // positions are relative to fset body := strings.Replace(source.String(), "+", "+", -1) body = strings.Replace(body, """, "\"", -1) body = strings.Replace(body, "'", "'", -1) body = strings.Replace(body, "&", "&", -1) body = strings.Replace(body, "<", "<", -1) body = strings.Replace(body, ">", ">", -1) f, err := parser.ParseFile(fset, "", body, 0) if err != nil { err = fmt.Errorf("Cannot parse file. err = %v", err) return } p.AddImport("unsafe") return f.Decls[0].(*goast.FuncDecl).Body.List[0].(*goast.AssignStmt).Rhs[0], leftType, preStmts, postStmts, nil } func transpileCompoundAssignOperator( n *ast.CompoundAssignOperator, p *program.Program, exprIsStmt bool) ( _ goast.Expr, _ string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpileCompoundAssignOperator. err = %v", err) } }() operator := getTokenForOperator(n.Opcode) right, rightType, newPre, newPost, err := atomicOperation(n.Children()[1], p) if err != nil { return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) left, leftType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false) if err != nil { return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) // Pointer arithmetic if types.IsPointer(p, n.Type) && (operator == token.ADD_ASSIGN || operator == token.SUB_ASSIGN) { operator = convertToWithoutAssign(operator) v, vType, newPre, newPost, err := pointerArithmetic(p, left, leftType, right, rightType, operator) if err != nil { return nil, "", nil, nil, err } if v == nil { return nil, "", nil, nil, fmt.Errorf("Expr is nil") } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) v = &goast.BinaryExpr{ X: left, Op: token.ASSIGN, Y: v, } return v, vType, preStmts, postStmts, nil } // The right hand argument of the shift left or shift right operators // in Go must be unsigned integers. In C, shifting with a negative shift // count is undefined behaviour (so we should be able to ignore that case). // To handle this, cast the shift count to a uint64. if operator == token.SHL_ASSIGN || operator == token.SHR_ASSIGN { right, err = types.CastExpr(p, right, rightType, "unsigned long long") p.AddMessage(p.GenerateWarningOrErrorMessage(err, n, right == nil)) if right == nil { right = util.NewNil() } } switch operator { case token.AND_ASSIGN, token.OR_ASSIGN, token.XOR_ASSIGN, token.AND_NOT_ASSIGN: right, err = types.CastExpr(p, right, rightType, leftType) p.AddMessage(p.GenerateWarningMessage(err, n)) } resolvedLeftType, err := types.ResolveType(p, leftType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } if right == nil { err = fmt.Errorf("Right part is nil. err = %v", err) return nil, "", nil, nil, err } if left == nil { err = fmt.Errorf("Left part is nil. err = %v", err) return nil, "", nil, nil, err } right, err = types.CastExpr(p, right, rightType, leftType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) } return util.NewBinaryExpr(left, operator, right, resolvedLeftType, exprIsStmt), n.Type, preStmts, postStmts, nil } // getTokenForOperator returns the Go operator token for the provided C // operator. func getTokenForOperator(operator string) token.Token { switch operator { // Arithmetic case "--": return token.DEC case "++": return token.INC case "+": return token.ADD case "-": return token.SUB case "*": return token.MUL case "/": return token.QUO case "%": return token.REM // Assignment case "=": return token.ASSIGN case "+=": return token.ADD_ASSIGN case "-=": return token.SUB_ASSIGN case "*=": return token.MUL_ASSIGN case "/=": return token.QUO_ASSIGN case "%=": return token.REM_ASSIGN case "&=": return token.AND_ASSIGN case "|=": return token.OR_ASSIGN case "^=": return token.XOR_ASSIGN case "<<=": return token.SHL_ASSIGN case ">>=": return token.SHR_ASSIGN // Bitwise case "&": return token.AND case "|": return token.OR case "~": return token.XOR case ">>": return token.SHR case "<<": return token.SHL case "^": return token.XOR // Comparison case ">=": return token.GEQ case "<=": return token.LEQ case "<": return token.LSS case ">": return token.GTR case "!=": return token.NEQ case "==": return token.EQL // Logical case "!": return token.NOT case "&&": return token.LAND case "||": return token.LOR // Other case ",": return token.COMMA } panic(fmt.Sprintf("unknown operator: %s", operator)) } func convertToWithoutAssign(operator token.Token) token.Token { switch operator { case token.ADD_ASSIGN: // "+=" return token.ADD case token.SUB_ASSIGN: // "-=" return token.SUB case token.MUL_ASSIGN: // "*=" return token.MUL case token.QUO_ASSIGN: // "/=" return token.QUO } panic(fmt.Sprintf("not support operator: %v", operator)) } func findUnaryWithInteger(node ast.Node) (*ast.UnaryOperator, bool) { switch n := node.(type) { case *ast.UnaryOperator: return n, true case *ast.ParenExpr: return findUnaryWithInteger(n.Children()[0]) } return nil, false } func atomicOperation(n ast.Node, p *program.Program) ( expr goast.Expr, exprType string, preStmts, postStmts []goast.Stmt, err error) { expr, exprType, preStmts, postStmts, err = transpileToExpr(n, p, false) if err != nil { return } defer func() { if err != nil { err = fmt.Errorf("Cannot create atomicOperation |%T|. err = %v", n, err) } }() switch v := n.(type) { case *ast.UnaryOperator: switch v.Operator { case "&", "*", "!", "-", "~": return } // UnaryOperator 0x252d798 'double' prefix '-' // `-FloatingLiteral 0x252d778 'double' 0.000000e+00 if _, ok := v.Children()[0].(*ast.IntegerLiteral); ok { return } if _, ok := v.Children()[0].(*ast.FloatingLiteral); ok { return } // ++, -- anonymous functions are handled here below expr, exprType, preStmts, postStmts, err = transpileToExpr(n, p, true) // UnaryOperator 0x3001768 'int' prefix '++' // `-DeclRefExpr 0x3001740 'int' lvalue Var 0x303e888 'current_test' 'int' // OR // UnaryOperator 0x3001768 'int' postfix '++' // `-DeclRefExpr 0x3001740 'int' lvalue Var 0x303e888 'current_test' 'int' var varName string var vv *ast.DeclRefExpr if vv, err = getSoleChildDeclRefExpr(v); err == nil { varName = vv.Name var exprResolveType string exprResolveType, err = types.ResolveType(p, v.Type) if err != nil { return } // operators: ++, -- if v.IsPrefix { // Example: // UnaryOperator 0x3001768 'int' prefix '++' // `-DeclRefExpr 0x3001740 'int' lvalue Var 0x303e888 'current_test' 'int' expr = util.NewAnonymousFunction(append(preStmts, &goast.ExprStmt{expr}), nil, util.NewIdent(varName), exprResolveType) preStmts = nil break } // Example: // UnaryOperator 0x3001768 'int' postfix '++' // `-DeclRefExpr 0x3001740 'int' lvalue Var 0x303e888 'current_test' 'int' expr = util.NewAnonymousFunction(preStmts, []goast.Stmt{&goast.ExprStmt{expr}}, util.NewIdent(varName), exprResolveType) preStmts = nil break } // UnaryOperator 0x358d470 'int' postfix '++' // `-MemberExpr 0x358d438 'int' lvalue .pos 0x358b538 // `-ArraySubscriptExpr 0x358d410 'struct struct_I_A':'struct struct_I_A' lvalue // |-ImplicitCastExpr 0x358d3f8 'struct struct_I_A *' // | `-DeclRefExpr 0x358d3b0 'struct struct_I_A [2]' lvalue Var 0x358b6e8 'siia' 'struct struct_I_A [2]' // `-IntegerLiteral 0x358d3d8 'int' 0 varName = "tempVar" expr, exprType, preStmts, postStmts, err = transpileToExpr(v.Children()[0], p, false) if err != nil { return } body := append(preStmts, &goast.AssignStmt{ Lhs: []goast.Expr{util.NewIdent(varName)}, Tok: token.DEFINE, Rhs: []goast.Expr{&goast.UnaryExpr{ Op: token.AND, X: expr, }}, }) deferBody := postStmts postStmts = nil preStmts = nil switch v.Operator { case "++": expr = &goast.BinaryExpr{ X: &goast.StarExpr{X: util.NewIdent(varName)}, Op: token.ADD_ASSIGN, Y: &goast.BasicLit{Kind: token.INT, Value: "1"}, } case "--": expr = &goast.BinaryExpr{ X: &goast.StarExpr{X: util.NewIdent(varName)}, Op: token.SUB_ASSIGN, Y: &goast.BasicLit{Kind: token.INT, Value: "1"}, } } body = append(body, preStmts...) deferBody = append(deferBody, postStmts...) var exprResolveType string exprResolveType, err = types.ResolveType(p, v.Type) if err != nil { return } // operators: ++, -- if v.IsPrefix { // Example: // UnaryOperator 0x3001768 'int' prefix '++' // `-DeclRefExpr 0x3001740 'int' lvalue Var 0x303e888 'current_test' 'int' expr = util.NewAnonymousFunction(append(body, &goast.ExprStmt{expr}), deferBody, &goast.StarExpr{ X: util.NewIdent(varName), }, exprResolveType) preStmts = nil postStmts = nil break } // Example: // UnaryOperator 0x3001768 'int' postfix '++' // `-DeclRefExpr 0x3001740 'int' lvalue Var 0x303e888 'current_test' 'int' expr = util.NewAnonymousFunction(body, append(deferBody, &goast.ExprStmt{expr}), &goast.StarExpr{ X: util.NewIdent(varName), }, exprResolveType) preStmts = nil postStmts = nil case *ast.CompoundAssignOperator: // CompoundAssignOperator 0x32911c0 'int' '-=' ComputeLHSTy='int' ComputeResultTy='int' // |-DeclRefExpr 0x3291178 'int' lvalue Var 0x328df60 'iterator' 'int' // `-IntegerLiteral 0x32911a0 'int' 2 if vv, ok := v.Children()[0].(*ast.DeclRefExpr); ok { var varName string varName = vv.Name var exprResolveType string exprResolveType, err = types.ResolveType(p, v.Type) if err != nil { return } // since we will explicitly use an anonymous function, we can transpileToExpr as a statement expr, exprType, preStmts, postStmts, err = transpileToExpr(n, p, true) expr = util.NewAnonymousFunction(append(preStmts, &goast.ExprStmt{expr}), postStmts, util.NewIdent(varName), exprResolveType) preStmts = nil postStmts = nil break } // CompoundAssignOperator 0x27906c8 'double' '+=' ComputeLHSTy='double' ComputeResultTy='double' // |-UnaryOperator 0x2790670 'double' lvalue prefix '*' // | `-ImplicitCastExpr 0x2790658 'double *' // | `-DeclRefExpr 0x2790630 'double *' lvalue Var 0x2790570 'p' 'double *' // `-IntegerLiteral 0x32911a0 'int' 2 if vv, ok := v.Children()[0].(*ast.UnaryOperator); ok && vv.IsPrefix && vv.Operator == "*" { if vvv, ok := vv.Children()[0].(*ast.ImplicitCastExpr); ok { if vvvv, ok := vvv.Children()[0].(*ast.DeclRefExpr); ok { if types.IsPointer(p, vvvv.Type) { var varName string varName = vvvv.Name var exprResolveType string exprResolveType, err = types.ResolveType(p, v.Type) if err != nil { return } expr = util.NewAnonymousFunction(append(preStmts, &goast.ExprStmt{expr}), postStmts, &goast.UnaryExpr{ Op: token.AND, X: util.NewIdent(varName), }, exprResolveType) preStmts = nil postStmts = nil break } } } } // CompoundAssignOperator 0x32911c0 'int' '-=' ComputeLHSTy='int' ComputeResultTy='int' // |-DeclRefExpr 0x3291178 'int' lvalue Var 0x328df60 'iterator' 'int' // `-IntegerLiteral 0x32911a0 'int' 2 varName := "tempVar" expr, exprType, preStmts, postStmts, err = transpileToExpr(v.Children()[0], p, false) if err != nil { return } body := append(preStmts, &goast.AssignStmt{ Lhs: []goast.Expr{util.NewIdent(varName)}, Tok: token.DEFINE, Rhs: []goast.Expr{&goast.UnaryExpr{ Op: token.AND, X: expr, }}, }) preStmts = nil // CompoundAssignOperator 0x27906c8 'double' '+=' ComputeLHSTy='double' ComputeResultTy='double' // |-UnaryOperator 0x2790670 'double' lvalue prefix '*' // | `-ImplicitCastExpr 0x2790658 'double *' // | `-DeclRefExpr 0x2790630 'double *' lvalue Var 0x2790570 'p' 'double *' // `-ImplicitCastExpr 0x27906b0 'double' // `-IntegerLiteral 0x2790690 'int' 1 var newPre, newPost []goast.Stmt expr, exprType, newPre, newPost, err = atomicOperation(v.Children()[1], p) if err != nil { return } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) var exprResolveType string exprResolveType, err = types.ResolveType(p, v.Type) if err != nil { return } body = append(preStmts, body...) body = append(body, &goast.AssignStmt{ Lhs: []goast.Expr{&goast.StarExpr{ X: util.NewIdent(varName), }}, Tok: getTokenForOperator(v.Opcode), Rhs: []goast.Expr{expr}, }) expr = util.NewAnonymousFunction(body, postStmts, &goast.StarExpr{ X: util.NewIdent(varName), }, exprResolveType) preStmts = nil postStmts = nil case *ast.ParenExpr: // ParenExpr 0x3c42468 'int' return atomicOperation(v.Children()[0], p) case *ast.ImplicitCastExpr: if _, ok := v.Children()[0].(*ast.MemberExpr); ok { return } if _, ok := v.Children()[0].(*ast.IntegerLiteral); ok { return } // for case : overflow char // ImplicitCastExpr 0x2027358 'char' // `-UnaryOperator 0x2027338 'int' prefix '-' // `-IntegerLiteral 0x2027318 'int' 1 // // another example : // ImplicitCastExpr 0x2982630 'char' // `-ParenExpr 0x2982610 'int' // `-UnaryOperator 0x29825f0 'int' prefix '-' // `-IntegerLiteral 0x29825d0 'int' 1 if v.Type == "char" { if len(v.Children()) == 1 { if u, ok := findUnaryWithInteger(n.Children()[0]); ok { if u.IsPrefix && u.Type == "int" && u.Operator == "-" { if _, ok := u.Children()[0].(*ast.IntegerLiteral); ok { return transpileToExpr(&ast.BinaryOperator{ Type: "int", Type2: "int", Operator: "+", ChildNodes: []ast.Node{ u, &ast.IntegerLiteral{ Type: "int", Value: "256", }, }, }, p, false) } } } } } expr, exprType, preStmts, postStmts, err = atomicOperation(v.Children()[0], p) if err != nil { return nil, "", nil, nil, err } if exprType == types.NullPointer { return } if !types.IsFunction(exprType) && !strings.ContainsAny(v.Type, "[]") { expr, err = types.CastExpr(p, expr, exprType, v.Type) if err != nil { return nil, "", nil, nil, err } exprType = v.Type } return case *ast.BinaryOperator: switch v.Operator { case ",": // BinaryOperator 0x35b95e8 'int' ',' // |-UnaryOperator 0x35b94b0 'int' postfix '++' // | `-DeclRefExpr 0x35b9488 'int' lvalue Var 0x35b8dc8 't' 'int' // `-CompoundAssignOperator 0x35b95b0 'int' '+=' ComputeLHSTy='int' ComputeResultTy='int' // |-MemberExpr 0x35b9558 'int' lvalue .pos 0x35b8730 // | `-ArraySubscriptExpr 0x35b9530 'struct struct_I_A4':'struct struct_I_A4' lvalue // | |-ImplicitCastExpr 0x35b9518 'struct struct_I_A4 *' // | | `-DeclRefExpr 0x35b94d0 'struct struct_I_A4 [2]' lvalue Var 0x35b88d8 'siia' 'struct struct_I_A4 [2]' // | `-IntegerLiteral 0x35b94f8 'int' 0 // `-IntegerLiteral 0x35b9590 'int' 1 // `-BinaryOperator 0x3c42440 'int' ',' // |-BinaryOperator 0x3c423d8 'int' '=' // | |-DeclRefExpr 0x3c42390 'int' lvalue Var 0x3c3cf60 'iterator' 'int' // | `-IntegerLiteral 0x3c423b8 'int' 0 // `-ImplicitCastExpr 0x3c42428 'int' // `-DeclRefExpr 0x3c42400 'int' lvalue Var 0x3c3cf60 'iterator' 'int' varName := "tempVar" expr, exprType, preStmts, postStmts, err = transpileToExpr(v.Children()[0], p, true) if err != nil { return } inBody := combineStmts(&goast.ExprStmt{expr}, preStmts, postStmts) preStmts = nil postStmts = nil expr, exprType, preStmts, postStmts, err = atomicOperation(v.Children()[1], p) if err != nil { return } if v, ok := expr.(*goast.CallExpr); ok { if vv, ok := v.Fun.(*goast.FuncLit); ok { vv.Body.List = append(inBody, vv.Body.List...) break } } body := append(inBody, preStmts...) preStmts = nil body = append(body, &goast.AssignStmt{ Lhs: []goast.Expr{util.NewIdent(varName)}, Tok: token.DEFINE, Rhs: []goast.Expr{&goast.UnaryExpr{ Op: token.AND, X: expr, }}, }) var exprResolveType string exprResolveType, err = types.ResolveType(p, v.Type) if err != nil { return } expr = util.NewAnonymousFunction(body, postStmts, &goast.UnaryExpr{ Op: token.MUL, X: util.NewIdent(varName), }, exprResolveType) preStmts = nil postStmts = nil exprType = v.Type return case "=": // BinaryOperator 0x2a230c0 'int' '=' // |-UnaryOperator 0x2a23080 'int' lvalue prefix '*' // | `-ImplicitCastExpr 0x2a23068 'int *' // | `-DeclRefExpr 0x2a23040 'int *' lvalue Var 0x2a22f20 'a' 'int *' // `-IntegerLiteral 0x2a230a0 'int' 42 // VarDecl 0x328dc50 col:13 used d 'int' cinit // `-BinaryOperator 0x328dd98 'int' '=' // |-DeclRefExpr 0x328dcb0 'int' lvalue Var 0x328dae8 'a' 'int' // `-BinaryOperator 0x328dd70 'int' '=' // |-DeclRefExpr 0x328dcd8 'int' lvalue Var 0x328db60 'b' 'int' // `-BinaryOperator 0x328dd48 'int' '=' // |-DeclRefExpr 0x328dd00 'int' lvalue Var 0x328dbd8 'c' 'int' // `-IntegerLiteral 0x328dd28 'int' 42 var body []goast.Stmt varName := "tempVar" var exprResolveType string exprResolveType, err = types.ResolveType(p, v.Type) if err != nil { return } e, _, newPre, newPost, _ := transpileToExpr(v, p, true) if assign, ok := e.(*goast.BinaryExpr); !ok || assign.Op != token.ASSIGN { panic("not a valid assignment") } else { body = append(body, &goast.AssignStmt{ Lhs: []goast.Expr{util.NewIdent(varName)}, Tok: token.DEFINE, Rhs: []goast.Expr{assign.Y}, }) body = append(body, &goast.ExprStmt{ &goast.BinaryExpr{ X: assign.X, Op: token.ASSIGN, Y: util.NewIdent(varName), }, }) } body = combineMultipleStmts(body, newPre, newPost) preStmts = nil postStmts = nil var returnValue goast.Expr = util.NewIdent(varName) expr = util.NewAnonymousFunction(body, nil, returnValue, exprResolveType) expr = &goast.ParenExpr{ X: expr, Lparen: 1, } } } return } // getDeclRefExpr - find ast DeclRefExpr // Examples of input ast trees: // UnaryOperator 0x2a23080 'int' lvalue prefix '*' // `-ImplicitCastExpr 0x2a23068 'int *' // `-DeclRefExpr 0x2a23040 'int *' lvalue Var 0x2a22f20 'a' 'int *' // // DeclRefExpr 0x328dd00 'int' lvalue Var 0x328dbd8 'c' 'int' func getDeclRefExpr(n ast.Node) (*ast.DeclRefExpr, bool) { switch v := n.(type) { case *ast.DeclRefExpr: return v, true case *ast.ImplicitCastExpr: return getDeclRefExpr(n.Children()[0]) case *ast.UnaryOperator: return getDeclRefExpr(n.Children()[0]) } return nil, false } c2go-0.26.10/transpiler/scope.go000066400000000000000000000022721410601753200163370ustar00rootroot00000000000000// This file contains functions for transpiling scopes. A scope is zero or more // statements between a set of curly brackets. package transpiler import ( "fmt" goast "go/ast" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" ) func transpileCompoundStmt(n *ast.CompoundStmt, p *program.Program) ( *goast.BlockStmt, []goast.Stmt, []goast.Stmt, error) { preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} stmts := []goast.Stmt{} for _, x := range n.Children() { result, err := transpileToStmts(x, p) if err != nil { return nil, nil, nil, err } if result != nil { stmts = append(stmts, result...) } } return &goast.BlockStmt{ List: stmts, }, preStmts, postStmts, nil } func transpileToBlockStmt(node ast.Node, p *program.Program) ( *goast.BlockStmt, []goast.Stmt, []goast.Stmt, error) { stmts, err := transpileToStmts(node, p) if err != nil { return nil, nil, nil, err } if len(stmts) == 1 { if block, ok := stmts[0].(*goast.BlockStmt); ok { return block, nil, nil, nil } } if stmts == nil { return nil, nil, nil, fmt.Errorf("Stmts inside Block cannot be nil") } return &goast.BlockStmt{ List: stmts, }, nil, nil, nil } c2go-0.26.10/transpiler/switch.go000066400000000000000000000367751410601753200165460ustar00rootroot00000000000000// This file contains functions for transpiling a "switch" statement. package transpiler import ( "fmt" goast "go/ast" "go/token" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/util" "golang.org/x/tools/go/ast/astutil" ) func transpileSwitchStmt(n *ast.SwitchStmt, p *program.Program) ( _ *goast.SwitchStmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpileSwitchStmt : err = %v", err) } }() // The first two children are nil. I don't know what they are supposed to be // for. It looks like the number of children is also not reliable, but we // know that we need the last two which represent the condition and body // respectively. if len(n.Children()) < 2 { // I don't know what causes this condition. Need to investigate. panic(fmt.Sprintf("Less than two children for switch: %#v", n)) } // The condition is the expression to be evaluated against each of the // cases. condition, _, newPre, newPost, err := transpileToExpr(n.Children()[len(n.Children())-2], p, false) if err != nil { return nil, nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) // separation body of switch on cases body := n.Children()[len(n.Children())-1].(*ast.CompoundStmt) // solving switch case without body // case -1: // default: ... bodyLen := len(body.Children()) for i := 0; i < bodyLen; i++ { cn := body.ChildNodes[i] cs, ok1 := cn.(*ast.CaseStmt) ds, ok2 := cn.(*ast.DefaultStmt) ls, ok3 := cn.(*ast.LabelStmt) if !ok1 && !ok2 && !ok3 || cn == nil || len(cn.Children()) == 0 { // Do not consider a node which is not a case, label or default statement here continue } lastCn := cn.Children()[len(cn.Children())-1] _, isCase := lastCn.(*ast.CaseStmt) _, isDefault := lastCn.(*ast.DefaultStmt) _, isLabel := lastCn.(*ast.LabelStmt) if isCase || isDefault || isLabel { // Insert lastCn before next case in body (https://github.com/golang/go/wiki/SliceTricks) body.ChildNodes = append(body.ChildNodes, &ast.CompoundStmt{}) copy(body.ChildNodes[i+2:], body.ChildNodes[i+1:]) body.ChildNodes[i+1] = lastCn bodyLen++ if len(cn.Children()) == 1 { // If cn child nodes would be empty without lastCn, // replace lastCn by an empty CompoundStmt cn.Children()[0] = &ast.CompoundStmt{} } else { // Remove lastCn from cn child nodes if ok1 { cs.ChildNodes = cs.ChildNodes[:len(cs.ChildNodes)-1] } if ok2 { ds.ChildNodes = ds.ChildNodes[:len(ds.ChildNodes)-1] } if ok3 { ls.ChildNodes = ls.ChildNodes[:len(ls.ChildNodes)-1] } } } } for i := range body.Children() { // For simplification - each CaseStmt will have CompoundStmt if v, ok := body.Children()[i].(*ast.CaseStmt); ok { if _, ok := v.Children()[len(v.Children())-1].(*ast.CompoundStmt); !ok { var compoundStmt ast.CompoundStmt compoundStmt.AddChild(v.Children()[len(v.Children())-1]) v.Children()[len(v.Children())-1] = &compoundStmt } } // For simplification - each DefaultStmt will have CompoundStmt if v, ok := body.Children()[i].(*ast.DefaultStmt); ok { if _, ok := v.Children()[len(v.Children())-1].(*ast.CompoundStmt); !ok { var compoundStmt ast.CompoundStmt compoundStmt.AddChild(v.Children()[len(v.Children())-1]) v.Children()[len(v.Children())-1] = &compoundStmt } } // For simplification - each LabelStmt will have CompoundStmt if v, ok := body.Children()[i].(*ast.LabelStmt); ok { if _, ok := v.Children()[len(v.Children())-1].(*ast.CompoundStmt); !ok { var compoundStmt ast.CompoundStmt compoundStmt.AddChild(v.Children()[len(v.Children())-1]) v.Children()[len(v.Children())-1] = &compoundStmt } } } hasLabelCase := false // Move element inside CompoundStmt for i := 0; i < len(body.Children()); i++ { switch body.Children()[i].(type) { case *ast.CaseStmt, *ast.DefaultStmt: // do nothing case *ast.LabelStmt: hasLabelCase = true // do nothing else default: if i != 0 { lastStmt := body.Children()[i-1].Children() if comp, ok := lastStmt[len(lastStmt)-1].(*ast.CompoundStmt); ok { // add node in CompoundStmt comp.AddChild(body.Children()[i]) // remove from body if i+1 < len(body.Children()) { body.ChildNodes = append(body.ChildNodes[:i], body.ChildNodes[i+1:]...) } else { body.ChildNodes = body.ChildNodes[:i] } // goto to last iteration i-- } else { p.AddMessage(p.GenerateWarningMessage( fmt.Errorf("Unexpected element"), n)) } } else { p.AddMessage(p.GenerateWarningMessage( fmt.Errorf("Unsupport case"), n)) } } } // The body will always be a CompoundStmt because a switch statement is not // valid without curly brackets. cases, newPre, newPost, err := normalizeSwitchCases(body, p) if err != nil { return nil, nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) // For simplification switch case: // from: // case 3: // { // var c int // return // } // fallthrough // to: // case 3: // var c int // return // for i := range cases { cs, ok := cases[i].(*goast.CaseClause) if !ok { continue } body := cs.Body if len(body) != 2 { continue } var isFallThrough bool if v, ok := body[1].(*goast.BranchStmt); ok { isFallThrough = (v.Tok == token.FALLTHROUGH) } if !isFallThrough { if len(body) > 1 { cs.Body = body } continue } if v, ok := body[0].(*goast.BlockStmt); ok { if len(v.List) > 0 { if vv, ok := v.List[len(v.List)-1].(*goast.BranchStmt); ok { if vv.Tok == token.BREAK { if isFallThrough { v.List = v.List[:len(v.List)-1] cs.Body = body[:len(body)-1] continue } } } if _, ok := v.List[len(v.List)-1].(*goast.ReturnStmt); ok { cs.Body = body[:len(body)-1] continue } } else { cs.Body = []goast.Stmt{body[1]} } } } // Convert the normalized cases back into statements so they can be children // of goast.SwitchStmt. stmts := []goast.Stmt{} for _, singleCase := range cases { if singleCase == nil { panic("nil single case") } stmts = append(stmts, singleCase) } if hasLabelCase { stmts, newPost = handleLabelCases(cases, p) preStmts, postStmts = combinePreAndPostStmts(preStmts, newPost, []goast.Stmt{}, postStmts) } return &goast.SwitchStmt{ Tag: condition, Body: &goast.BlockStmt{ List: stmts, }, }, preStmts, postStmts, nil } func normalizeSwitchCases(body *ast.CompoundStmt, p *program.Program) ( _ []goast.Stmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { // The body of a switch has a non uniform structure. For example: // // switch a { // case 1: // foo(); // bar(); // break; // default: // baz(); // qux(); // } // // Looks like: // // *ast.CompountStmt // *ast.CaseStmt // case 1: // *ast.CallExpr // foo() // *ast.CallExpr // bar() // *ast.BreakStmt // break // *ast.DefaultStmt // default: // *ast.CallExpr // baz() // *ast.CallExpr // qux() // // Each of the cases contains one child that is the first statement, but all // the rest are children of the parent CompountStmt. This makes it // especially tricky when we want to remove the 'break' or add a // 'fallthrough'. // // To make it easier we normalise the cases. This means that we iterate // through all of the statements of the CompountStmt and merge any children // that are not 'case' or 'break' with the previous node to give us a // structure like: // // []*goast.CaseClause // *goast.CaseClause // case 1: // *goast.CallExpr // foo() // *goast.CallExpr // bar() // // *ast.BreakStmt // break (was removed) // *goast.CaseClause // default: // *goast.CallExpr // baz() // *goast.CallExpr // qux() // // During this translation we also remove 'break' or append a 'fallthrough'. cases := []goast.Stmt{} caseEndedWithBreak := false for _, x := range body.Children() { switch c := x.(type) { case *ast.CaseStmt, *ast.DefaultStmt, *ast.LabelStmt: var newPre, newPost []goast.Stmt cases, newPre, newPost, err = appendCaseOrDefaultToNormalizedCases(cases, c, caseEndedWithBreak, p) if err != nil { return []goast.Stmt{}, nil, nil, err } caseEndedWithBreak = false preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) case *ast.BreakStmt: caseEndedWithBreak = true default: var stmt goast.Stmt var newPre, newPost []goast.Stmt stmt, newPre, newPost, err = transpileToStmt(x, p) if err != nil { return []goast.Stmt{}, nil, nil, err } preStmts = append(preStmts, newPre...) preStmts = append(preStmts, stmt) preStmts = append(preStmts, newPost...) } } return cases, preStmts, postStmts, nil } func appendCaseOrDefaultToNormalizedCases(cases []goast.Stmt, stmt ast.Node, caseEndedWithBreak bool, p *program.Program) ( []goast.Stmt, []goast.Stmt, []goast.Stmt, error) { preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} if len(cases) > 0 && !caseEndedWithBreak { if cs, ok := cases[len(cases)-1].(*goast.CaseClause); ok { cs.Body = append(cs.Body, &goast.BranchStmt{ Tok: token.FALLTHROUGH, }) } if ls, ok := cases[len(cases)-1].(*goast.LabeledStmt); ok { ft := &goast.BranchStmt{ Tok: token.FALLTHROUGH, } if _, ok2 := ls.Stmt.(*goast.EmptyStmt); ok2 { ls.Stmt = ft } else if bs, ok2 := ls.Stmt.(*goast.BlockStmt); ok2 { bs.List = append(bs.List, ft) } else { ls.Stmt = &goast.BlockStmt{ List: []goast.Stmt{ ls.Stmt, ft, }, } } } } caseEndedWithBreak = false var singleCase goast.Stmt var err error var newPre []goast.Stmt var newPost []goast.Stmt switch c := stmt.(type) { case *ast.CaseStmt: singleCase, newPre, newPost, err = transpileCaseStmt(c, p) case *ast.DefaultStmt: singleCase, err = transpileDefaultStmt(c, p) case *ast.LabelStmt: singleCase, newPre, newPost, err = transpileLabelStmt(c, p) lc, ok := singleCase.(*goast.LabeledStmt) if !ok { panic("expected *goast.LabeledStmt") } if len(newPost) == 1 { lc.Stmt = newPost[0] } else if len(newPost) > 1 { lc.Stmt = &goast.BlockStmt{ List: newPost, } } newPost = []goast.Stmt{} } if singleCase != nil { cases = append(cases, singleCase) } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) if err != nil { return []goast.Stmt{}, nil, nil, err } return cases, preStmts, postStmts, nil } func transpileCaseStmt(n *ast.CaseStmt, p *program.Program) ( *goast.CaseClause, []goast.Stmt, []goast.Stmt, error) { preStmts := []goast.Stmt{} postStmts := []goast.Stmt{} c, _, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false) if err != nil { return nil, nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) stmts, err := transpileStmts(n.Children()[1:], p) if err != nil { return nil, nil, nil, err } return &goast.CaseClause{ List: []goast.Expr{c}, Body: stmts, }, preStmts, postStmts, nil } func transpileDefaultStmt(n *ast.DefaultStmt, p *program.Program) (*goast.CaseClause, error) { stmts, err := transpileStmts(n.Children()[0:], p) if err != nil { return nil, err } return &goast.CaseClause{ List: nil, Body: stmts, }, nil } func handleLabelCases(cases []goast.Stmt, p *program.Program) (newCases []goast.Stmt, postStmts []goast.Stmt) { // In C a switch can have labels before a case. // Go does not support this. // To make it work we translate the switch cases as labels to blocks appended to the switch // For example: // // switch a { // case 1: // foo(); // break; // LABEL: // case 2: // bar(); // default: // baz(); // } // // is transpiled as: // // switch a { // case 1: // goto SW_1_1 // case 2: // goto SW_1_2 // default: // goto SW_1_3 // } // SW_1_1: // foo() // goto SW_1_END // LABEL: // ; // SW_1_2: // bar() // SW_1_3: // baz() // SW_1_END: // ; swEndLabel := p.GetNextIdentifier("SW_GENERATED_LABEL_") postStmts = append(postStmts, &goast.BranchStmt{ Label: util.NewIdent(swEndLabel), Tok: token.GOTO, }) funcTransformBreak := func(cursor *astutil.Cursor) bool { if cursor == nil { return true } node := cursor.Node() if bs, ok := node.(*goast.BranchStmt); ok { if bs.Tok == token.BREAK { cursor.Replace(&goast.BranchStmt{ Label: util.NewIdent(swEndLabel), Tok: token.GOTO, }) } } if _, ok := node.(*goast.ForStmt); ok { return false } if _, ok := node.(*goast.RangeStmt); ok { return false } if _, ok := node.(*goast.SwitchStmt); ok { return false } if _, ok := node.(*goast.TypeSwitchStmt); ok { return false } if _, ok := node.(*goast.SelectStmt); ok { return false } return true } for i, x := range cases { switch c := x.(type) { case *goast.CaseClause: caseLabel := p.GetNextIdentifier("SW_GENERATED_LABEL_") if len(c.Body) == 0 { c.Body = append(c.Body, &goast.BranchStmt{ Tok: token.BREAK, }) } var isFallThrough bool // Remove fallthrough if v, ok := c.Body[len(c.Body)-1].(*goast.BranchStmt); ok { isFallThrough = (v.Tok == token.FALLTHROUGH) c.Body = c.Body[:len(c.Body)-1] } if len(c.Body) == 0 { c.Body = append(c.Body, &goast.EmptyStmt{}) } // Replace break's with goto swEndLabel astutil.Apply(c, funcTransformBreak, nil) body := c.Body // append caseLabel label followed by case body postStmts = append(postStmts, &goast.LabeledStmt{ Label: util.NewIdent(caseLabel), Stmt: body[0], }) body = body[1:] postStmts = append(postStmts, body...) // If not last case && no fallthrough goto swEndLabel if i != len(cases)-1 && !isFallThrough { postStmts = append(postStmts, &goast.BranchStmt{ Label: util.NewIdent(swEndLabel), Tok: token.GOTO, }) } // In switch case we goto caseLabel c.Body = []goast.Stmt{ &goast.BranchStmt{ Label: util.NewIdent(caseLabel), Tok: token.GOTO, }, } newCases = append(newCases, c) case *goast.LabeledStmt: var isFallThrough bool // Remove fallthrough if it's the only statement if v, ok := c.Stmt.(*goast.BranchStmt); ok { if v.Tok == token.FALLTHROUGH { c.Stmt = &goast.EmptyStmt{} isFallThrough = true } } else if b, ok := c.Stmt.(*goast.BlockStmt); ok { // Remove fallthrough if LabeledStmt contains a BlockStmt if v, ok := b.List[len(b.List)-1].(*goast.BranchStmt); ok { if v.Tok == token.FALLTHROUGH { b.List = b.List[:len(b.List)-1] isFallThrough = true } } } // Replace break's with goto swEndLabel astutil.Apply(c, funcTransformBreak, nil) // append label followed by label body postStmts = append(postStmts, c) // If not last case && no fallthrough goto swEndLabel if i != len(cases)-1 && !isFallThrough { postStmts = append(postStmts, &goast.BranchStmt{ Label: util.NewIdent(swEndLabel), Tok: token.GOTO, }) } } } postStmts = append(postStmts, &goast.LabeledStmt{ Label: util.NewIdent(swEndLabel), Stmt: &goast.EmptyStmt{}, }) return } c2go-0.26.10/transpiler/translation_unit.go000066400000000000000000000106231410601753200206220ustar00rootroot00000000000000package transpiler import ( goast "go/ast" "strings" "fmt" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "reflect" ) func transpileTranslationUnitDecl(p *program.Program, n *ast.TranslationUnitDecl) ( decls []goast.Decl, err error) { for i := 0; i < len(n.Children()); i++ { presentNode := n.Children()[i] var runAfter func() if rec, ok := presentNode.(*ast.RecordDecl); ok { if i+1 < len(n.Children()) { switch recNode := n.Children()[i+1].(type) { case *ast.VarDecl: name := types.GenerateCorrectType(types.CleanCType(recNode.Type)) if rec.Name == "" { recNode.Type = types.GenerateCorrectType(recNode.Type) recNode.Type2 = types.GenerateCorrectType(recNode.Type2) if strings.HasPrefix(name, "union ") { rec.Name = name[len("union "):] recNode.Type = types.CleanCType("union " + name) } if strings.HasPrefix(name, "struct ") { name = types.GetBaseType(name) rec.Name = name[len("struct "):] } } case *ast.TypedefDecl: if isSameTypedefNames(recNode) && !rec.Definition { // this is just the declaration of a type, the implementation comes later i++ continue } name := types.GenerateCorrectType(types.CleanCType(recNode.Type)) if isSameTypedefNames(recNode) { i++ // continue on, so that this type is defined } else if strings.HasPrefix(name, "union ") { if recNode.Type == "union "+rec.Name { names := []string{rec.Name, recNode.Name} for _, name := range names { rec.Name = name var d []goast.Decl d, err = transpileToNode(rec, p) if err != nil { p.AddMessage(p.GenerateErrorMessage(err, n)) err = nil } else { decls = append(decls, d...) } } i++ continue } else { rec.Name = name[len("union "):] recNode.Type = types.CleanCType("union " + name) } } else if strings.HasPrefix(name, "struct ") { if rec.Name != "" { runAfter = func() { var d []goast.Decl d, err = transpileToNode(recNode, p) if err != nil { p.AddMessage(p.GenerateErrorMessage(err, n)) err = nil } else { decls = append(decls, d...) } } i++ } else { rec.Name = name[len("struct "):] recNode.Type = types.CleanCType("struct " + name) } } if !rec.Definition { // This was not the real definition of the type, // we have to go and look it up var typeToDeclare *ast.RecordDecl records := ast.GetAllNodesOfType(recNode, reflect.TypeOf(&ast.Record{})) if len(records) > 0 { record := records[0].(*ast.Record) if n, ok := p.NodeMap[record.Addr]; ok { if toDeclare, ok2 := n.(*ast.RecordDecl); ok2 { typeToDeclare = toDeclare } } } if typeToDeclare == nil { p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("could not lookup type definition for : %v", rec.Name), rec)) typeToDeclare = rec } p.DeclareType(typeToDeclare, types.GenerateCorrectType(rec.Name)) if runAfter != nil { runAfter() } continue } } } } var d []goast.Decl d, err = transpileToNode(presentNode, p) if err != nil { p.AddMessage(p.GenerateErrorMessage(err, n)) err = nil } else { decls = append(decls, d...) if runAfter != nil { runAfter() } } } return } func isSameTypedefNames(v *ast.TypedefDecl) bool { // for structs : /* TypedefDecl 0x33da010 col:21 referenced Uq 'struct Uq':'struct Uq' `-ElaboratedType 0x33d9fc0 'struct Uq' sugar `-RecordType 0x33d9fa0 'struct Uq' `-Record 0x33da090 'Uq' */ // for unions: /* TypedefDecl 0x38bc070 col:23 referenced myunion 'union myunion':'union myunion' `-ElaboratedType 0x38bc020 'union myunion' sugar `-RecordType 0x38bc000 'union myunion' `-Record 0x38bc0d8 'myunion' */ if ("struct "+v.Name == v.Type2 || "union "+v.Name == v.Type2) && v.Type == v.Type2 { if vv, ok := v.Children()[0].(*ast.ElaboratedType); ok && vv.Type == v.Type { if vvv, ok := vv.Children()[0].(*ast.RecordType); ok && vvv.Type == v.Type2 { if vvvv, ok := vvv.Children()[0].(*ast.Record); ok && vvvv.Type == v.Name { return true } } } } return false } c2go-0.26.10/transpiler/transpiler.go000066400000000000000000000310531410601753200174100ustar00rootroot00000000000000// Package transpiler handles the conversion between the Clang AST and the Go // AST. package transpiler import ( "errors" "fmt" goast "go/ast" "go/parser" "go/token" "strings" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" ) // TranspileAST iterates through the Clang AST and builds a Go AST func TranspileAST(fileName, packageName string, p *program.Program, root ast.Node) error { // Start by parsing an empty file. p.FileSet = token.NewFileSet() packageSignature := fmt.Sprintf("package %v", packageName) f, err := parser.ParseFile(p.FileSet, fileName, packageSignature, 0) p.File = f if err != nil { return err } // Now begin building the Go AST. decls, err := transpileToNode(root, p) if err != nil { p.AddMessage(p.GenerateErrorMessage(fmt.Errorf("Error of transpiling: err = %v", err), root)) err = nil // Error is ignored } p.File.Decls = append(p.File.Decls, decls...) if p.OutputAsTest { p.AddImport("testing") p.AddImport("io/ioutil") p.AddImport("os") // TODO: There should be a cleaner way to add a function to the program. // This code was taken from the end of transpileFunctionDecl. p.File.Decls = append(p.File.Decls, &goast.FuncDecl{ Name: util.NewIdent("TestApp"), Type: &goast.FuncType{ Params: &goast.FieldList{ List: []*goast.Field{ { Names: []*goast.Ident{util.NewIdent("t")}, Type: util.NewTypeIdent("*testing.T"), }, }, }, }, Body: &goast.BlockStmt{ List: []goast.Stmt{ util.NewExprStmt(&goast.Ident{Name: "os.Chdir(\"../../..\")"}), // "go test" does not redirect stdin to the executable // running the test so we need to override them in the test // itself. See documentation for noarch.Stdin. util.NewExprStmt(&goast.Ident{Name: "ioutil.WriteFile(\"build/stdin\", []byte{'7'}, 0777)"}), util.NewExprStmt( &goast.Ident{Name: "stdin, _ := os.Open(\"build/stdin\")"}, ), util.NewExprStmt(util.NewBinaryExpr( &goast.Ident{Name: "noarch.Stdin"}, token.ASSIGN, &goast.Ident{Name: "noarch.NewFile(stdin)"}, "*noarch.File", true, )), util.NewExprStmt(util.NewCallExpr("main")), }, }, }) } if list := p.StartupStatements(); len(list) > 0 { // Now we need to build the init() function. This sets up certain state // and variables that the runtime expects to be ready. p.File.Decls = append(p.File.Decls, &goast.FuncDecl{ Name: goast.NewIdent("init"), Type: util.NewFuncType(&goast.FieldList{}, "", false), Body: &goast.BlockStmt{ List: list, }, }) } // only for "stdbool.h" if p.IncludeHeaderIsExists("stdbool.h") { p.File.Decls = append(p.File.Decls, &goast.GenDecl{ Tok: token.TYPE, Specs: []goast.Spec{ &goast.TypeSpec{ Name: goast.NewIdent("_Bool"), Type: goast.NewIdent("int8"), }, }, }) } // Add the imports after everything else so we can ensure that they are all // placed at the top. for _, quotedImportPath := range p.Imports() { importSpec := &goast.ImportSpec{ Path: &goast.BasicLit{ Kind: token.IMPORT, Value: quotedImportPath, }, } importDecl := &goast.GenDecl{ Tok: token.IMPORT, } importDecl.Specs = append(importDecl.Specs, importSpec) p.File.Decls = append([]goast.Decl{importDecl}, p.File.Decls...) } return err } func transpileToExpr(node ast.Node, p *program.Program, exprIsStmt bool) ( expr goast.Expr, exprType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpileToExpr. err = %v", err) } }() if node == nil { panic(node) } defer func() { preStmts = nilFilterStmts(preStmts) postStmts = nilFilterStmts(postStmts) }() switch n := node.(type) { case *ast.StringLiteral: expr = transpileStringLiteral(n) exprType = "const char *" case *ast.FloatingLiteral: expr = transpileFloatingLiteral(n) exprType = "double" err = nil case *ast.ConstantExpr: expr, exprType, err = transpileConstantExpr(n, p) case *ast.PredefinedExpr: expr, exprType, err = transpilePredefinedExpr(n, p) case *ast.ConditionalOperator: expr, exprType, preStmts, postStmts, err = transpileConditionalOperator(n, p) case *ast.ArraySubscriptExpr: expr, exprType, preStmts, postStmts, err = transpileArraySubscriptExpr(n, p, exprIsStmt) case *ast.BinaryOperator: expr, exprType, preStmts, postStmts, err = transpileBinaryOperator(n, p, exprIsStmt) case *ast.UnaryOperator: expr, exprType, preStmts, postStmts, err = transpileUnaryOperator(n, p, exprIsStmt) case *ast.MemberExpr: expr, exprType, preStmts, postStmts, err = transpileMemberExpr(n, p) case *ast.ImplicitCastExpr: expr, exprType, preStmts, postStmts, err = transpileImplicitCastExpr(n, p, exprIsStmt) case *ast.DeclRefExpr: expr, exprType, err = transpileDeclRefExpr(n, p) case *ast.IntegerLiteral: expr, exprType, err = transpileIntegerLiteral(n), "int", nil case *ast.ParenExpr: expr, exprType, preStmts, postStmts, err = transpileParenExpr(n, p) case *ast.CStyleCastExpr: expr, exprType, preStmts, postStmts, err = transpileCStyleCastExpr(n, p, exprIsStmt) case *ast.CharacterLiteral: expr, exprType, err = transpileCharacterLiteral(n), "char", nil case *ast.CallExpr: expr, exprType, preStmts, postStmts, err = transpileCallExpr(n, p) case *ast.CompoundAssignOperator: return transpileCompoundAssignOperator(n, p, exprIsStmt) case *ast.UnaryExprOrTypeTraitExpr: return transpileUnaryExprOrTypeTraitExpr(n, p) case *ast.InitListExpr: expr, exprType, err = transpileInitListExpr(n, p) case *ast.CompoundLiteralExpr: expr, exprType, err = transpileCompoundLiteralExpr(n, p) case *ast.StmtExpr: return transpileStmtExpr(n, p) case *ast.ImplicitValueInitExpr: cType := n.Type1 if strings.HasPrefix(cType, "struct ") { s := p.Structs[cType] if s == nil { return nil, "", nil, nil, fmt.Errorf("cannot found struct with name: `%s`", cType) } expr = &goast.CompositeLit{ Type: util.NewIdent(cType[len("struct "):]), Lbrace: 1, } return } s := p.Structs["struct "+cType] if s == nil { return nil, "", nil, nil, fmt.Errorf("cannot found struct with name: `%s`", cType) } expr = &goast.CompositeLit{ Type: util.NewIdent(cType), Lbrace: 1, } default: p.AddMessage(p.GenerateWarningMessage(errors.New("cannot transpile to expr"), node)) expr = util.NewNil() } // Real return is through named arguments. return } func transpileToStmts(node ast.Node, p *program.Program) (stmts []goast.Stmt, err error) { if node == nil { return nil, nil } defer func() { stmts = nilFilterStmts(stmts) }() switch n := node.(type) { case *ast.DeclStmt: stmts, err = transpileDeclStmt(n, p) if err != nil { p.AddMessage(p.GenerateErrorMessage(fmt.Errorf("Error in DeclStmt: %v", err), n)) err = nil // Error is ignored } return } var ( stmt goast.Stmt preStmts []goast.Stmt postStmts []goast.Stmt ) stmt, preStmts, postStmts, err = transpileToStmt(node, p) if err != nil { p.AddMessage(p.GenerateErrorMessage(fmt.Errorf("Error in DeclStmt: %v", err), node)) err = nil // Error is ignored } return stripParentheses(combineStmts(stmt, preStmts, postStmts)), err } func stripParentheses(stmts []goast.Stmt) []goast.Stmt { for _, s := range stmts { if es, ok := s.(*goast.ExprStmt); ok { for { if pe, ok2 := es.X.(*goast.ParenExpr); ok2 { es.X = pe.X } else { break } } } } return stmts } func transpileToStmt(node ast.Node, p *program.Program) ( stmt goast.Stmt, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { if node == nil { return } defer func() { if err != nil { p.AddMessage(p.GenerateErrorMessage(err, node)) err = nil // Error is ignored } }() defer func() { preStmts = nilFilterStmts(preStmts) postStmts = nilFilterStmts(postStmts) }() var expr goast.Expr switch n := node.(type) { case *ast.DefaultStmt: stmt, err = transpileDefaultStmt(n, p) return case *ast.CaseStmt: stmt, preStmts, postStmts, err = transpileCaseStmt(n, p) return case *ast.SwitchStmt: stmt, preStmts, postStmts, err = transpileSwitchStmt(n, p) return case *ast.BreakStmt: stmt = &goast.BranchStmt{ Tok: token.BREAK, } return case *ast.WhileStmt: return transpileWhileStmt(n, p) case *ast.DoStmt: return transpileDoStmt(n, p) case *ast.ContinueStmt: stmt, err = transpileContinueStmt(n, p) return case *ast.IfStmt: stmt, preStmts, postStmts, err = transpileIfStmt(n, p) return case *ast.ForStmt: return transpileForStmt(n, p) case *ast.ReturnStmt: return transpileReturnStmt(n, p) case *ast.CompoundStmt: stmt, preStmts, postStmts, err = transpileCompoundStmt(n, p) return case *ast.BinaryOperator: if n.Operator == "," { stmt, preStmts, err = transpileBinaryOperatorComma(n, p) return } case *ast.LabelStmt: stmt, preStmts, postStmts, err = transpileLabelStmt(n, p) return case *ast.GotoStmt: stmt, err = transpileGotoStmt(n, p) return case *ast.GCCAsmStmt: // Go does not support inline assembly. See: // https://github.com/elliotchance/c2go/issues/228 p.AddMessage(p.GenerateWarningMessage( errors.New("cannot transpile asm, will be ignored"), n)) stmt = &goast.EmptyStmt{} return case *ast.DeclStmt: var stmts []goast.Stmt stmts, err = transpileDeclStmt(n, p) if err != nil { return } stmt = stmts[len(stmts)-1] if len(stmts) > 1 { preStmts = stmts[0 : len(stmts)-2] } return } // We do not care about the return type. var theType string expr, theType, preStmts, postStmts, err = transpileToExpr(node, p, true) if err != nil { return } // nil is happen, when we remove function `free` of // see function CallExpr in transpiler if expr == (*goast.CallExpr)(nil) { return } // CStyleCastExpr.Kind == ToVoid var foundToVoid bool if theType == types.ToVoid { foundToVoid = true } if v, ok := node.(*ast.CStyleCastExpr); ok && v.Kind == ast.CStyleCastExprToVoid { foundToVoid = true } if len(node.Children()) > 0 { if v, ok := node.Children()[0].(*ast.CStyleCastExpr); ok && v.Kind == ast.CStyleCastExprToVoid { foundToVoid = true } } if foundToVoid { stmt = &goast.AssignStmt{ Lhs: []goast.Expr{goast.NewIdent("_")}, Tok: token.ASSIGN, Rhs: []goast.Expr{expr}, } return } // For all other cases if expr == nil { err = fmt.Errorf("Expr is nil") return } stmt = util.NewExprStmt(expr) return } func transpileToNode(node ast.Node, p *program.Program) (decls []goast.Decl, err error) { defer func() { if err != nil { p.AddMessage(p.GenerateErrorMessage(err, node)) err = nil // Error is ignored } }() switch n := node.(type) { case *ast.TranslationUnitDecl: decls, err = transpileTranslationUnitDecl(p, n) case *ast.FunctionDecl: decls, err = transpileFunctionDecl(n, p) if len(decls) > 0 { if _, ok := decls[0].(*goast.FuncDecl); ok { decls[0].(*goast.FuncDecl).Doc = p.GetMessageComments() decls[0].(*goast.FuncDecl).Doc.List = append(decls[0].(*goast.FuncDecl).Doc.List, p.GetComments(node.Position())...) decls[0].(*goast.FuncDecl).Doc.List = append([]*goast.Comment{&goast.Comment{ Text: fmt.Sprintf("// %s - transpiled function from %s", decls[0].(*goast.FuncDecl).Name.Name, node.Position().GetSimpleLocation()), }}, decls[0].(*goast.FuncDecl).Doc.List...) } } case *ast.TypedefDecl: decls, err = transpileTypedefDecl(p, n) case *ast.RecordDecl: decls, err = transpileRecordDecl(p, n) case *ast.VarDecl: decls, _, err = transpileVarDecl(p, n) case *ast.EnumDecl: decls, err = transpileEnumDecl(p, n) case *ast.EmptyDecl: if len(n.Children()) == 0 { // ignore if length is zero, for avoid // mistake warning } else { p.AddMessage(p.GenerateWarningMessage(fmt.Errorf("EmptyDecl is not transpiled"), n)) } err = nil return default: panic(fmt.Sprintf("cannot transpile to node: %#v", node)) } return } func transpileStmts(nodes []ast.Node, p *program.Program) (stmts []goast.Stmt, err error) { defer func() { if err != nil { p.AddMessage(p.GenerateErrorMessage(fmt.Errorf("Error in transpileToStmts: %v", err), nodes[0])) err = nil // Error is ignored } }() for _, s := range nodes { if s != nil { var ( stmt goast.Stmt preStmts []goast.Stmt postStmts []goast.Stmt ) stmt, preStmts, postStmts, err = transpileToStmt(s, p) if err != nil { return } stmts = append(stmts, combineStmts(stmt, preStmts, postStmts)...) } } return stmts, nil } c2go-0.26.10/transpiler/unary.go000066400000000000000000000457771410601753200164050ustar00rootroot00000000000000// This file contains functions for transpiling unary operator expressions. package transpiler import ( "fmt" "strings" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" goast "go/ast" "go/token" ) func transpileUnaryOperatorInc(n *ast.UnaryOperator, p *program.Program, operator token.Token, exprIsStmt bool) ( expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpileUnaryOperatorInc. err = %v", err) } }() if !(operator == token.INC || operator == token.DEC) { err = fmt.Errorf("not acceptable operator '%v'", operator) return } if types.IsPointer(p, n.Type) { switch operator { case token.INC: operator = token.ADD case token.DEC: operator = token.SUB } var e ast.Node e, err = getSoleChildIncrementable(n) if err != nil { return } var left goast.Expr var leftType string var newPre, newPost []goast.Stmt left, leftType, newPre, newPost, err = transpileToExpr(e, p, false) if err != nil { return } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) rightType := "int" right := &goast.BasicLit{ Kind: token.INT, Value: "1", } expr, eType, newPre, newPost, err = pointerArithmetic(p, left, leftType, right, rightType, operator) if err != nil { return } if expr == nil { return nil, "", nil, nil, fmt.Errorf("Expr is nil") } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) expr = &goast.BinaryExpr{ X: left, Op: token.ASSIGN, Y: expr, } if !exprIsStmt { var lType string lType, err = types.ResolveType(p, leftType) if err != nil { return } expr = util.NewAnonymousFunction([]goast.Stmt{&goast.ExprStmt{ X: expr, }}, nil, left, lType) } return } if v, ok := n.Children()[0].(*ast.DeclRefExpr); ok { switch n.Operator { case "++": return &goast.BinaryExpr{ X: util.NewIdent(v.Name), Op: token.ADD_ASSIGN, Y: &goast.BasicLit{Kind: token.INT, Value: "1"}, }, n.Type, nil, nil, nil case "--": return &goast.BinaryExpr{ X: util.NewIdent(v.Name), Op: token.SUB_ASSIGN, Y: &goast.BasicLit{Kind: token.INT, Value: "1"}, }, n.Type, nil, nil, nil } } // Unfortunately we cannot use the Go increment operators because we are not // providing any position information for tokens. This means that the ++/-- // would be placed before the expression and would be invalid in Go. // // Until it can be properly fixed (can we trick Go into to placing it after // the expression with a magic position?) we will have to return a // BinaryExpr with the same functionality. binaryOperator := "+=" if operator == token.DEC { binaryOperator = "-=" } return transpileBinaryOperator(&ast.BinaryOperator{ Type: n.Type, Operator: binaryOperator, ChildNodes: []ast.Node{ n.Children()[0], &ast.IntegerLiteral{ Type: "int", Value: "1", ChildNodes: []ast.Node{}, }, }, }, p, exprIsStmt) } func getSoleChildIncrementable(n ast.Node) (result ast.Node, err error) { children := n.Children() if len(children) != 1 { return nil, fmt.Errorf("expected one child node, got %d", len(children)) } switch c := children[0].(type) { case *ast.ParenExpr: return getSoleChildIncrementable(c) case *ast.DeclRefExpr, *ast.MemberExpr, *ast.UnaryOperator: return c, nil default: return nil, fmt.Errorf("unsupported type %T", c) } } func getSoleChildDeclRefExpr(n *ast.UnaryOperator) (result *ast.DeclRefExpr, err error) { var inspect ast.Node = n for { if inspect == nil { break } if ret, ok := inspect.Children()[0].(*ast.DeclRefExpr); ok { return ret, nil } if len(inspect.Children()) > 1 { return nil, fmt.Errorf("node has to many children: %T", inspect) } else if len(inspect.Children()) == 1 { if _, ok := inspect.Children()[0].(*ast.ParenExpr); !ok { err = fmt.Errorf("unsupported type %T", n.Children()[0]) return } inspect = inspect.Children()[0] } else { break } } return nil, fmt.Errorf("could not find supported type DeclRefExpr") } func transpileUnaryOperatorNot(n *ast.UnaryOperator, p *program.Program) ( goast.Expr, string, []goast.Stmt, []goast.Stmt, error) { e, eType, preStmts, postStmts, err := transpileToExpr(n.Children()[0], p, false) if err != nil { return nil, "", nil, nil, err } // null in C is zero if eType == types.NullPointer { e = &goast.BasicLit{ Kind: token.INT, Value: "0", } eType = "int" } if eType == "bool" { return &goast.UnaryExpr{ X: e, Op: token.NOT, }, "bool", preStmts, postStmts, nil } if strings.HasSuffix(eType, "*") { // `!pointer` has to be converted to `pointer == nil` return &goast.BinaryExpr{ X: e, Op: token.EQL, Y: util.NewIdent("nil"), }, "bool", preStmts, postStmts, nil } t, err := types.ResolveType(p, eType) p.AddMessage(p.GenerateWarningMessage(err, n)) if t == "*byte" { return util.NewUnaryExpr( token.NOT, util.NewCallExpr("noarch.CStringIsNull", e), ), "bool", preStmts, postStmts, nil } // only if added "stdbool.h" if p.IncludeHeaderIsExists("stdbool.h") { if t == "_Bool" { t = "int8" e = &goast.CallExpr{ Fun: goast.NewIdent("int8"), Lparen: 1, Args: []goast.Expr{e}, } } } p.AddImport("github.com/elliotchance/c2go/noarch") functionName := fmt.Sprintf("noarch.Not%s", util.GetExportedName(t)) return util.NewCallExpr(functionName, e), eType, preStmts, postStmts, nil } // tranpileUnaryOperatorAmpersant - operator ampersant & // Example of AST: // `-ImplicitCastExpr 0x2d0fe38 'int *' // `-UnaryOperator 0x2d0fe18 'int (*)[5]' prefix '&' // `-DeclRefExpr 0x2d0fdc0 'int [5]' lvalue Var 0x2d0fb20 'arr' 'int [5]' func transpileUnaryOperatorAmpersant(n *ast.UnaryOperator, p *program.Program) ( expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpileUnaryOperatorAmpersant : err = %v", err) } }() expr, eType, preStmts, postStmts, err = transpileToExpr(n.Children()[0], p, false) if err != nil { return } if expr == nil { err = fmt.Errorf("Expr is nil") return } if types.IsFunction(eType) { return } if types.IsLastArray(eType) { // In : eType = 'int [5]' // Out: eType = 'int *' f := strings.Index(eType, "[") e := strings.Index(eType, "]") if e == len(eType)-1 { eType = eType[:f] + "*" } else { eType = eType[:f] + "*" + eType[e+1:] } expr = &goast.UnaryExpr{ X: &goast.IndexExpr{ X: expr, Index: util.NewIntLit(0), }, Op: token.AND, } return } // In : eType = 'int' // Out: eType = 'int *' // FIXME: This will need to use a real slice to reference the original // value. _, err = types.ResolveType(p, eType) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, n)) return } p.AddImport("unsafe") expr = &goast.UnaryExpr{ X: expr, Op: token.AND, } // We now have a pointer to the original type. eType += " *" return } // transpilePointerArith - transpile pointer arithmetic // Example of using: // *(t + 1) = ... func transpilePointerArith(n *ast.UnaryOperator, p *program.Program) ( expr goast.Expr, eType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { // pointer - expression with name of array pointer var pointer interface{} // locationPointer var locPointer ast.Node var locPosition int // counter - count of amount of changes in AST tree var counter int var parents []ast.Node var found bool var f func(ast.Node) f = func(n ast.Node) { for i := range n.Children() { switch v := n.Children()[i].(type) { case *ast.ArraySubscriptExpr, *ast.UnaryOperator, *ast.DeclRefExpr: counter++ if counter > 1 { err = fmt.Errorf("Not acceptable : change counter is more then 1. found = %T,%T", pointer, v) return } // found pointer pointer = v // Replace pointer to zero var zero ast.IntegerLiteral zero.Type = "int" zero.Value = "0" locPointer = n locPosition = i n.Children()[i] = &zero found = true return case *ast.CStyleCastExpr: if v.Type == "int" { continue } counter++ if counter > 1 { err = fmt.Errorf("Not acceptable : change counter is more then 1. found = %T,%T", pointer, v) return } // found pointer pointer = v // Replace pointer to zero var zero ast.IntegerLiteral zero.Type = "int" zero.Value = "0" locPointer = n locPosition = i n.Children()[i] = &zero found = true return case *ast.MemberExpr: // check - if member of union a := n.Children()[i] var isUnion bool for { if a == nil { break } if len(a.Children()) == 0 { break } switch vv := a.Children()[0].(type) { case *ast.MemberExpr, *ast.DeclRefExpr: var typeVV string if vvv, ok := vv.(*ast.MemberExpr); ok { typeVV = vvv.Type } if vvv, ok := vv.(*ast.DeclRefExpr); ok { typeVV = vvv.Type } typeVV = types.GetBaseType(typeVV) if _, ok := p.Structs[typeVV]; ok { isUnion = true } if _, ok := p.Structs["struct "+typeVV]; ok { isUnion = true } if strings.HasPrefix(typeVV, "union ") || strings.HasPrefix(typeVV, "struct ") { isUnion = true } if isUnion { break } a = vv continue case *ast.ImplicitCastExpr, *ast.CStyleCastExpr: a = vv continue } break } if isUnion { counter++ if counter > 1 { err = fmt.Errorf("Not acceptable : change counter is more then 1. found = %v,%v", pointer, v) return } // found pointer pointer = v // Replace pointer to zero var zero ast.IntegerLiteral zero.Type = "int" zero.Value = "0" locPointer = n locPosition = i n.Children()[i] = &zero found = true return } // member of struct f(v) case *ast.CallExpr: if v.Type == "int" { continue } counter++ if counter > 1 { err = fmt.Errorf("Not acceptable : change counter is more then 1. found = %T,%T", pointer, v) return } // found pointer pointer = v // Replace pointer to zero var zero ast.IntegerLiteral zero.Type = "int" zero.Value = "0" locPointer = n locPosition = i n.Children()[i] = &zero found = true return default: if found { break } if len(v.Children()) > 0 { if found { break } parents = append(parents, v) deep := true if vv, ok := v.(*ast.ImplicitCastExpr); ok && types.IsCInteger(p, vv.Type) { deep = false } if vv, ok := v.(*ast.CStyleCastExpr); ok && types.IsCInteger(p, vv.Type) { deep = false } if deep { f(v) } if !found { parents = parents[:len(parents)-1] } } } } } f(n) if err != nil { return } if pointer == nil { err = fmt.Errorf("pointer is nil") return } defer func() { if pointer != nil && locPointer != nil { locPointer.Children()[locPosition] = pointer.(ast.Node) } }() var typesParentBefore []string for i := range parents { switch v := parents[i].(type) { case *ast.ParenExpr: typesParentBefore = append(typesParentBefore, v.Type) v.Type = "int" case *ast.BinaryOperator: typesParentBefore = append(typesParentBefore, v.Type) v.Type = "int" case *ast.ImplicitCastExpr: typesParentBefore = append(typesParentBefore, v.Type) v.Type = "int" case *ast.CStyleCastExpr: typesParentBefore = append(typesParentBefore, v.Type) v.Type = "int" case *ast.VAArgExpr: typesParentBefore = append(typesParentBefore, v.Type) v.Type = "int" case *ast.MemberExpr: typesParentBefore = append(typesParentBefore, v.Type) v.Type = "int" default: panic(fmt.Errorf("Not support parent type %T in pointer searching", v)) } } defer func() { for i := range parents { switch v := parents[i].(type) { case *ast.ParenExpr: v.Type = typesParentBefore[i] case *ast.BinaryOperator: v.Type = typesParentBefore[i] case *ast.ImplicitCastExpr: v.Type = typesParentBefore[i] case *ast.CStyleCastExpr: v.Type = typesParentBefore[i] case *ast.VAArgExpr: v.Type = typesParentBefore[i] case *ast.MemberExpr: v.Type = typesParentBefore[i] default: panic(fmt.Errorf("Not support parent type %T in pointer searching", v)) } } }() e, eType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false) if err != nil { return } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) eType = n.Type switch v := pointer.(type) { case *ast.MemberExpr: arr, arrType, newPre, newPost, err2 := transpileToExpr(v, p, false) if err2 != nil { return } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) isConst, indexInt := util.EvaluateConstExpr(e) if isConst && indexInt == 0 { // nop } else if isConst && indexInt < 0 { indexInt = -indexInt arr, _, newPre, newPost, err = pointerArithmetic(p, arr, arrType, util.NewIntLit(int(indexInt)), "int", token.SUB) } else { arr, _, newPre, newPost, err = pointerArithmetic(p, arr, arrType, e, eType, token.ADD) } return &goast.StarExpr{ X: arr, }, eType, preStmts, postStmts, err case *ast.DeclRefExpr: var ident goast.Expr ident = util.NewIdent(v.Name) isConst, indexInt := util.EvaluateConstExpr(e) if isConst && indexInt == 0 { if strings.HasSuffix(v.Type, "]") { return &goast.IndexExpr{ X: ident, Index: util.NewIntLit(0), }, eType, preStmts, postStmts, err } } else if isConst && indexInt < 0 { indexInt = -indexInt ident, _, newPre, newPost, err = pointerArithmetic(p, ident, n.Type+" *", util.NewIntLit(int(indexInt)), "int", token.SUB) } else { ident, _, newPre, newPost, err = pointerArithmetic(p, ident, n.Type+" *", e, eType, token.ADD) } return &goast.StarExpr{ X: ident, }, eType, preStmts, postStmts, err case *ast.ArraySubscriptExpr, *ast.CallExpr, *ast.CStyleCastExpr: arr, arrType, newPre, newPost, err2 := transpileToExpr(v.(ast.Node), p, false) if err2 != nil { return } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) isConst, indexInt := util.EvaluateConstExpr(e) if isConst && indexInt == 0 { // nop } else if isConst && indexInt < 0 { indexInt = -indexInt arr, _, newPre, newPost, err = pointerArithmetic(p, arr, arrType, util.NewIntLit(int(indexInt)), "int", token.SUB) } else { arr, _, newPre, newPost, err = pointerArithmetic(p, arr, arrType, e, eType, token.ADD) } return &goast.StarExpr{ X: arr, }, eType, preStmts, postStmts, err case *ast.UnaryOperator: arr, arrType, newPre, newPost, err2 := atomicOperation(v, p) if err2 != nil { return } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) if memberName, ok := getMemberName(n.Children()[0]); ok { return &goast.StarExpr{ X: &goast.SelectorExpr{ X: arr, Sel: util.NewIdent(memberName), }, }, eType, preStmts, postStmts, err } isConst, indexInt := util.EvaluateConstExpr(e) if isConst && indexInt == 0 { // nop } else if isConst && indexInt < 0 { indexInt = -indexInt arr, _, newPre, newPost, err = pointerArithmetic(p, arr, arrType, util.NewIntLit(int(indexInt)), "int", token.SUB) } else { arr, _, newPre, newPost, err = pointerArithmetic(p, arr, arrType, e, eType, token.ADD) } return &goast.StarExpr{ X: arr, }, eType, preStmts, postStmts, err } return nil, "", nil, nil, fmt.Errorf("Cannot found : %#v", pointer) } func transpileUnaryOperator(n *ast.UnaryOperator, p *program.Program, exprIsStmt bool) ( _ goast.Expr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpile UnaryOperator: err = %v", err) p.AddMessage(p.GenerateWarningMessage(err, n)) } }() operator := getTokenForOperator(n.Operator) switch operator { case token.MUL: // * // Prefix "*" is not a multiplication. // Prefix "*" used for pointer arithmetic // Example of using: // *(t + 1) = ... return transpilePointerArith(n, p) case token.INC, token.DEC: // ++, -- return transpileUnaryOperatorInc(n, p, operator, exprIsStmt) case token.NOT: // ! return transpileUnaryOperatorNot(n, p) case token.AND: // & return transpileUnaryOperatorAmpersant(n, p) } // Otherwise handle like a unary operator. e, eType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, exprIsStmt) if err != nil { return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) return &goast.UnaryExpr{ Op: operator, X: e, }, eType, preStmts, postStmts, nil } func transpileUnaryExprOrTypeTraitExpr(n *ast.UnaryExprOrTypeTraitExpr, p *program.Program) ( *goast.BasicLit, string, []goast.Stmt, []goast.Stmt, error) { t := n.Type2 // It will have children if the sizeof() is referencing a variable. // Fortunately clang already has the type in the AST for us. if len(n.Children()) > 0 { var realFirstChild interface{} t = "" switch c := n.Children()[0].(type) { case *ast.ParenExpr: realFirstChild = c.Children()[0] case *ast.DeclRefExpr: t = c.Type default: panic(fmt.Sprintf("cannot find first child from: %#v", n.Children()[0])) } if t == "" { switch ty := realFirstChild.(type) { case *ast.DeclRefExpr: t = ty.Type2 case *ast.ArraySubscriptExpr: t = ty.Type case *ast.MemberExpr: t = ty.Type case *ast.UnaryOperator: t = ty.Type case *ast.ParenExpr: t = ty.Type case *ast.CallExpr: t = ty.Type case *ast.CStyleCastExpr: t = ty.Type case *ast.ConditionalOperator: t = ty.Type case *ast.BinaryOperator: t = ty.Type case *ast.IntegerLiteral: t = ty.Type case *ast.StringLiteral: t = ty.Type default: panic(fmt.Sprintf("cannot do unary on: %#v", ty)) } } } sizeInBytes, err := types.SizeOf(p, t) p.AddMessage(p.GenerateWarningMessage(err, n)) return util.NewIntLit(sizeInBytes), n.Type1, nil, nil, nil } func transpileStmtExpr(n *ast.StmtExpr, p *program.Program) ( *goast.CallExpr, string, []goast.Stmt, []goast.Stmt, error) { returnType, err := types.ResolveType(p, n.Type) if err != nil { return nil, "", nil, nil, err } body, pre, post, err := transpileCompoundStmt(n.Children()[0].(*ast.CompoundStmt), p) if err != nil { return nil, "", pre, post, err } // The body of the StmtExpr is always a CompoundStmt. However, the last // statement needs to be transformed into an explicit return statement. lastStmt := body.List[len(body.List)-1] body.List[len(body.List)-1] = &goast.ReturnStmt{ Results: []goast.Expr{lastStmt.(*goast.ExprStmt).X}, } return util.NewFuncClosure(returnType, body.List...), n.Type, pre, post, nil } c2go-0.26.10/transpiler/union.go000066400000000000000000000046021410601753200163550ustar00rootroot00000000000000package transpiler import ( "bytes" "fmt" "html/template" goast "go/ast" "go/format" "go/parser" "go/token" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" ) func transpileUnion(name string, size int, fields []*goast.Field) ( _ []goast.Decl, err error) { type field struct { Name string TypeField string } type union struct { Name string Size int Fields []field } src := `package main import( "unsafe" "reflect" ) type {{ .Name }} struct{ memory unsafe.Pointer } func (unionVar * {{ .Name }}) copy() ( {{ .Name }}){ var buffer [{{ .Size }}]byte for i := range buffer{ buffer[i] = (*((*[{{ .Size }}]byte)(unionVar.memory)))[i] } var newUnion {{ .Name }} newUnion.memory = unsafe.Pointer(&buffer) return newUnion } {{ range .Fields }} func (unionVar * {{ $.Name }}) {{ .Name }}() (*{{ .TypeField }}){ if unionVar.memory == nil{ var buffer [{{ $.Size }}]byte unionVar.memory = unsafe.Pointer(&buffer) } return (*{{ .TypeField }})(unionVar.memory) } {{ end }} ` // Generate structure of union var un union un.Name = name un.Size = size for i := range fields { var f field f.Name = fields[i].Names[0].Name var buf bytes.Buffer err = format.Node(&buf, token.NewFileSet(), fields[i].Type) if err != nil { err = fmt.Errorf("cannot parse type '%s' : %v", fields[i].Type, err) return } f.TypeField = buf.String() un.Fields = append(un.Fields, f) } tmpl := template.Must(template.New("").Parse(src)) var source bytes.Buffer err = tmpl.Execute(&source, un) if err != nil { err = fmt.Errorf("cannot execute template \"%s\" for data %v : %v", source.String(), un, err) return } // Create the AST by parsing src. fset := token.NewFileSet() // positions are relative to fset f, err := parser.ParseFile(fset, "", source.String(), 0) if err != nil { err = fmt.Errorf("cannot parse source \"%s\" : %v", source.String(), err) return } return f.Decls[1:], nil } func isUnionMemberExpr(p *program.Program, n *ast.MemberExpr) (IsUnion bool) { if len(n.Children()) > 0 { if v, ok := n.Children()[0].(*ast.MemberExpr); ok { if p.IsUnion(v.Type) { IsUnion = true } } if v, ok := n.Children()[0].(*ast.DeclRefExpr); ok { if p.IsUnion(v.Type) { IsUnion = true } } if v, ok := n.Children()[0].(*ast.ImplicitCastExpr); ok { if p.IsUnion(v.Type) { IsUnion = true } } } return } c2go-0.26.10/transpiler/util.go000066400000000000000000000041071410601753200162020ustar00rootroot00000000000000// This file contains utility and helper methods for the transpiler. package transpiler import ( "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" goast "go/ast" "reflect" ) func isNil(stmt goast.Stmt) bool { if stmt == nil { return true } return reflect.ValueOf(stmt).IsNil() } func convertDeclToStmt(decls []goast.Decl) (stmts []goast.Stmt) { for i := range decls { if decls[i] != nil { stmts = append(stmts, &goast.DeclStmt{Decl: decls[i]}) } } return } func combinePreAndPostStmts( pre []goast.Stmt, post []goast.Stmt, newPre []goast.Stmt, newPost []goast.Stmt) ([]goast.Stmt, []goast.Stmt) { pre = append(pre, nilFilterStmts(newPre)...) post = append(post, nilFilterStmts(newPost)...) return pre, post } // nilFilterStmts - remove nil stmt from slice func nilFilterStmts(stmts []goast.Stmt) (out []goast.Stmt) { out = make([]goast.Stmt, 0, len(stmts)) for _, stmt := range stmts { if !isNil(stmt) { out = append(out, stmt) } } return } // combineStmts - combine elements to slice func combineStmts(stmt goast.Stmt, preStmts, postStmts []goast.Stmt) (stmts []goast.Stmt) { stmts = make([]goast.Stmt, 0, 1+len(preStmts)+len(postStmts)) preStmts = nilFilterStmts(preStmts) if preStmts != nil { stmts = append(stmts, preStmts...) } if !isNil(stmt) { stmts = append(stmts, stmt) } postStmts = nilFilterStmts(postStmts) if postStmts != nil { stmts = append(stmts, postStmts...) } return } // combineMultipleStmts - combine elements to slice func combineMultipleStmts(stmts, preStmts, postStmts []goast.Stmt) []goast.Stmt { return combineStmts(nil, preStmts, append(stmts, postStmts...)) } // GetUintptrForPointer - return uintptr for pointer // Example : uint64(uintptr(unsafe.Pointer( ...pointer... ))) func GetUintptrForPointer(p *program.Program, expr goast.Expr, exprType string) (goast.Expr, string, error) { returnType := "long long" expr, err := types.CastExpr(p, expr, exprType, "void*") return util.NewCallExpr("int64", util.NewCallExpr("uintptr", expr)), returnType, err } c2go-0.26.10/transpiler/variables.go000066400000000000000000000311211410601753200171710ustar00rootroot00000000000000package transpiler import ( "fmt" "strings" "github.com/elliotchance/c2go/ast" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" "github.com/elliotchance/c2go/util" goast "go/ast" "go/parser" "go/token" ) // This map is used to rename struct member names. var structFieldTranslations = map[string]map[string]string{ "div_t": { "quot": "Quot", "rem": "Rem", }, "ldiv_t": { "quot": "Quot", "rem": "Rem", }, "lldiv_t": { "quot": "Quot", "rem": "Rem", }, "struct tm": { "tm_sec": "Tm_sec", "tm_min": "Tm_min", "tm_hour": "Tm_hour", "tm_mday": "Tm_mday", "tm_mon": "Tm_mon", "tm_year": "Tm_year", "tm_wday": "Tm_wday", "tm_yday": "Tm_yday", "tm_isdst": "Tm_isdst", }, } func transpileDeclRefExpr(n *ast.DeclRefExpr, p *program.Program) ( expr *goast.Ident, exprType string, err error) { if n.For == "EnumConstant" { // clang don`t show enum constant with enum type, // so we have to use hack for repair the type if v, ok := p.EnumConstantToEnum[n.Name]; ok { expr, exprType, err = util.NewIdent(n.Name), v, nil return } } theType := n.Type // FIXME: This is for linux to make sure the globals have the right type. if n.Name == "stdout" || n.Name == "stdin" || n.Name == "stderr" { theType = "FILE *" } return util.NewIdent(n.Name), theType, nil } func getDefaultValueForVar(p *program.Program, a *ast.VarDecl) ( _ []goast.Expr, _ string, _ []goast.Stmt, _ []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot getDefaultValueForVar : err = %v", err) } }() if len(a.Children()) == 0 { return nil, "", nil, nil, nil } // Memory allocation is translated into the Go-style. if allocSize := getAllocationSizeNode(p, a.Children()[0]); allocSize != nil { // type var t string if v, ok := a.Children()[0].(*ast.ImplicitCastExpr); ok { t = v.Type } if v, ok := a.Children()[0].(*ast.CStyleCastExpr); ok { t = v.Type } if v, ok := a.Children()[0].(*ast.CallExpr); ok { t = v.Type } if t != "" { right, newPre, newPost, err := generateAlloc(p, allocSize, t) if err != nil { p.AddMessage(p.GenerateWarningMessage(err, a)) return nil, "", nil, nil, err } return []goast.Expr{right}, t, newPre, newPost, nil } } if va, ok := a.Children()[0].(*ast.VAArgExpr); ok { outType, err := types.ResolveType(p, va.Type) if err != nil { return nil, "", nil, nil, err } if a, ok := va.Children()[0].(*ast.ImplicitCastExpr); ok { } else { return nil, "", nil, nil, fmt.Errorf("Expect ImplicitCastExpr for vaar, but we have %T", a) } src := fmt.Sprintf(`package main var temp = func() %s { var ret %s if v, ok := c2goVaList.Args[c2goVaList.Pos].(int32); ok{ // for 'rune' type ret = %s(v) } else { ret = c2goVaList.Args[c2goVaList.Pos].(%s) } c2goVaList.Pos++ return ret }()`, outType, outType, outType, outType) // Create the AST by parsing src. fset := token.NewFileSet() // positions are relative to fset f, err := parser.ParseFile(fset, "", src, 0) if err != nil { return nil, "", nil, nil, err } expr := f.Decls[0].(*goast.GenDecl).Specs[0].(*goast.ValueSpec).Values return expr, va.Type, nil, nil, nil } defaultValue, defaultValueType, newPre, newPost, err := atomicOperation(a.Children()[0], p) if err != nil { return nil, defaultValueType, newPre, newPost, err } var values []goast.Expr if !types.IsNullExpr(defaultValue) { t, err := types.CastExpr(p, defaultValue, defaultValueType, a.Type) if !p.AddMessage(p.GenerateWarningMessage(err, a)) { values = append(values, t) defaultValueType = a.Type } } return values, defaultValueType, newPre, newPost, nil } // GenerateFuncType in according to types /* Type: *ast.FuncType { . Func: 13:7 . Params: *ast.FieldList { . . Opening: 13:12 . . List: []*ast.Field (len = 2) { . . . 0: *ast.Field { . . . . Type: *ast.Ident { . . . . . NamePos: 13:13 . . . . . Name: "int" . . . . } . . . } . . . 1: *ast.Field { . . . . Type: *ast.Ident { . . . . . NamePos: 13:17 . . . . . Name: "int" . . . . } . . . } . . } . . Closing: 13:20 . } . Results: *ast.FieldList { . . Opening: - . . List: []*ast.Field (len = 1) { . . . 0: *ast.Field { . . . . Type: *ast.Ident { . . . . . NamePos: 13:21 . . . . . Name: "string" . . . . } . . . } . . } . . Closing: - . } } */ func GenerateFuncType(fields, returns []string) *goast.FuncType { var ft goast.FuncType { var fieldList goast.FieldList fieldList.Opening = 1 fieldList.Closing = 2 for i := range fields { fieldList.List = append(fieldList.List, &goast.Field{Type: &goast.Ident{Name: fields[i]}}) } ft.Params = &fieldList } { var fieldList goast.FieldList for i := range returns { fieldList.List = append(fieldList.List, &goast.Field{Type: &goast.Ident{Name: returns[i]}}) } ft.Results = &fieldList } return &ft } func transpileInitListExpr(e *ast.InitListExpr, p *program.Program) (goast.Expr, string, error) { resp := []goast.Expr{} var hasArrayFiller = false e.Type1 = types.GenerateCorrectType(e.Type1) e.Type2 = types.GenerateCorrectType(e.Type2) var goType string arrayType, arraySize := types.GetArrayTypeAndSize(e.Type1) if arraySize != -1 { goArrayType, err := types.ResolveType(p, arrayType) if err == nil { goType = goArrayType } } else { goType2, err := types.ResolveType(p, e.Type1) if err == nil { goType = goType2 } } var goStruct *program.Struct if e.Type1 == e.Type2 { goStruct = p.GetStruct(goType) if goStruct == nil { goStruct = p.GetStruct("struct " + goType) } } fieldIndex := 0 for _, node := range e.Children() { // Skip ArrayFiller if _, ok := node.(*ast.ArrayFiller); ok { hasArrayFiller = true continue } var expr goast.Expr var exprType string var err error expr, exprType, _, _, err = transpileToExpr(node, p, true) if err != nil { return nil, "", err } if goStruct != nil { if fieldIndex >= len(goStruct.FieldNames) { // index out of range goto CONTINUE_INIT } fn := goStruct.FieldNames[fieldIndex] if _, ok := goStruct.Fields[fn]; !ok { // field name not in map goto CONTINUE_INIT } if field, ok := goStruct.Fields[goStruct.FieldNames[fieldIndex]].(string); ok { expr2, err := types.CastExpr(p, expr, exprType, field) if err == nil { expr = expr2 } } fieldIndex++ } CONTINUE_INIT: resp = append(resp, expr) } var t goast.Expr var cTypeString string arrayType, arraySize = types.GetArrayTypeAndSize(e.Type1) if arraySize != -1 { goArrayType, err := types.ResolveType(p, arrayType) p.AddMessage(p.GenerateWarningMessage(err, e)) cTypeString = fmt.Sprintf("%s[%d]", arrayType, arraySize) if hasArrayFiller { t = &goast.ArrayType{ Elt: &goast.Ident{ Name: goArrayType, }, Len: util.NewIntLit(arraySize), } // Array fillers do not work with slices. // We initialize the array first, then convert to a slice. // For example: (&[4]int{1,2})[:] return &goast.SliceExpr{ X: &goast.ParenExpr{ X: &goast.UnaryExpr{ Op: token.AND, X: &goast.CompositeLit{ Type: t, Elts: resp, }, }, }, }, cTypeString, nil } t = &goast.ArrayType{ Elt: &goast.Ident{ Name: goArrayType, }, } } else { goType, err := types.ResolveType(p, e.Type1) if err != nil { return nil, "", err } t = &goast.Ident{ Name: goType, } cTypeString = e.Type1 } return &goast.CompositeLit{ Type: t, Elts: resp, }, cTypeString, nil } func transpileDeclStmt(n *ast.DeclStmt, p *program.Program) (stmts []goast.Stmt, err error) { if len(n.Children()) == 0 { return } var tud ast.TranslationUnitDecl tud.ChildNodes = n.Children() var decls []goast.Decl decls, err = transpileToNode(&tud, p) if err != nil { p.AddMessage(p.GenerateErrorMessage(err, n)) err = nil } stmts = convertDeclToStmt(decls) return } func transpileArraySubscriptExpr(n *ast.ArraySubscriptExpr, p *program.Program, exprIsStmt bool) ( _ goast.Expr, theType string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot transpile ArraySubscriptExpr. err = %v", err) p.AddMessage(p.GenerateWarningMessage(err, n)) } }() children := n.Children() expression, leftType, newPre, newPost, err := transpileToExpr(children[0], p, exprIsStmt) if err != nil { return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) index, indexType, newPre, newPost, err := atomicOperation(children[1], p) if err != nil { return nil, "", nil, nil, err } preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) if se, ok := expression.(*goast.SliceExpr); ok && se.High == nil && se.Low == nil && se.Max == nil { // simplify the expression expression = se.X } isConst, indexInt := util.EvaluateConstExpr(index) if isConst && indexInt < 0 { indexInt = -indexInt expression, leftType, newPre, newPost, err = pointerArithmetic(p, expression, leftType, util.NewIntLit(int(indexInt)), "int", token.SUB) return &goast.StarExpr{ X: expression, }, n.Type, newPre, newPost, err } else { resolvedLeftType, err := types.ResolveType(p, leftType) if err != nil { return nil, "", nil, nil, err } if types.IsPurePointer(p, resolvedLeftType) { if !isConst || indexInt != 0 { expression, leftType, newPre, newPost, err = pointerArithmetic(p, expression, leftType, index, indexType, token.ADD) } return &goast.StarExpr{ X: expression, }, n.Type, newPre, newPost, err } } return &goast.IndexExpr{ X: expression, Index: index, }, n.Type, preStmts, postStmts, nil } func transpileMemberExpr(n *ast.MemberExpr, p *program.Program) ( _ goast.Expr, _ string, preStmts []goast.Stmt, postStmts []goast.Stmt, err error) { n.Type = types.GenerateCorrectType(n.Type) n.Type2 = types.GenerateCorrectType(n.Type2) lhs, lhsType, newPre, newPost, err := transpileToExpr(n.Children()[0], p, false) if err != nil { return nil, "", nil, nil, err } lhsType = types.GenerateCorrectType(lhsType) lhsType = types.CleanCType(lhsType) preStmts, postStmts = combinePreAndPostStmts(preStmts, postStmts, newPre, newPost) lhsResolvedType, err := types.ResolveType(p, lhsType) p.AddMessage(p.GenerateWarningMessage(err, n)) // lhsType will be something like "struct foo" structType := p.GetStruct(lhsType) // added for support "struct typedef" if structType == nil { structType = p.GetStruct("struct " + lhsType) } // added for support "union typedef" if structType == nil { structType = p.GetStruct("union " + lhsType) } rhs := n.Name rhsType := "void *" if structType == nil { // This case should not happen in the future. Any structs should be // either parsed correctly from the source or be manually setup when the // parser starts if the struct if hidden or shared between libraries. // // Some other things to keep in mind: // 1. Types need to be stripped of their pointer, 'FILE *' -> 'FILE'. // 2. Types may refer to one or more other types in a chain that have // to be resolved before the real field type can be determined. err = fmt.Errorf("cannot determine type for LHS '%v'"+ ", will use 'void *' for all fields. Is lvalue = %v", lhsType, n.IsLvalue) p.AddMessage(p.GenerateWarningMessage(err, n)) } else { if s, ok := structType.Fields[rhs].(string); ok { rhsType = s } else { err = fmt.Errorf("cannot determine type for RHS '%v', will use"+ " 'void *' for all fields. Is lvalue = %v", rhs, n.IsLvalue) p.AddMessage(p.GenerateWarningMessage(err, n)) } } // FIXME: This is just a hack if util.InStrings(lhsResolvedType, []string{"darwin.Float2", "darwin.Double2"}) { rhs = util.GetExportedName(rhs) rhsType = "int" } x := lhs if n.IsPointer { x = &goast.ParenExpr{ X: &goast.StarExpr{X: x}, } } // Check for member name translation. lhsType = strings.TrimSpace(lhsType) if lhsType[len(lhsType)-1] == '*' { lhsType = lhsType[:len(lhsType)-len(" *")] } if member, ok := structFieldTranslations[lhsType]; ok { if alias, ok := member[rhs]; ok { rhs = alias } } // anonymous struct member? if rhs == "" { rhs = "anon" } if isUnionMemberExpr(p, n) { return &goast.ParenExpr{ Lparen: 1, X: &goast.StarExpr{ Star: 1, X: &goast.CallExpr{ Fun: &goast.SelectorExpr{ X: x, Sel: util.NewIdent(rhs), }, Lparen: 1, }, }, }, n.Type, preStmts, postStmts, nil } _ = rhsType return &goast.SelectorExpr{ X: x, Sel: util.NewIdent(rhs), }, n.Type, preStmts, postStmts, nil } c2go-0.26.10/travis/000077500000000000000000000000001410601753200140215ustar00rootroot00000000000000c2go-0.26.10/travis/lint.sh000077500000000000000000000002421410601753200153240ustar00rootroot00000000000000#!/bin/bash set -e # Check go fmt first if [ -n "$(gofmt -l .)" ]; then echo "Go code is not properly formatted. Use 'gofmt'." gofmt -d . exit 1 fi c2go-0.26.10/travis/test.sh000077500000000000000000000124021410601753200153360ustar00rootroot00000000000000#!/bin/bash set -e OUTFILE=/tmp/out.txt function cleanup { EXIT_STATUS=$? if [ $EXIT_STATUS != 0 ]; then [ ! -f $OUTFILE ] || cat $OUTFILE fi exit $EXIT_STATUS } trap cleanup EXIT echo "" > coverage.txt # The code below was copied from: # https://github.com/golang/go/issues/6909#issuecomment-232878416 # # As in @rodrigocorsi2 comment above (using full path to grep due to 'grep -n' # alias). export PKGS=$(go list ./... | grep -v c2go/build | grep -v /vendor/) # Make comma-separated. export PKGS_DELIM=$(echo "$PKGS" | paste -sd "," -) # Run tests and append all output to out.txt. It's important we have "-v" so # that all the test names are printed. It's also important that the covermode be # set to "count" so that the coverage profiles can be merged correctly together # with gocovmerge. # # Exit code 123 will be returned if any of the tests fail. rm -f $OUTFILE go list -f 'go test -v -tags integration -race -covermode atomic -coverprofile {{.Name}}.coverprofile -coverpkg $PKGS_DELIM {{.ImportPath}}' $PKGS | xargs -I{} bash -c "{} >> $OUTFILE" # Merge coverage profiles. COVERAGE_FILES=`ls -1 *.coverprofile 2>/dev/null | wc -l` if [ $COVERAGE_FILES != 0 ]; then # check program `gocovmerge` is exist if which gocovmerge >/dev/null 2>&1; then gocovmerge `ls *.coverprofile` > coverage.txt rm *.coverprofile fi fi # Print stats UNIT_TESTS=$(grep "=== RUN" $OUTFILE | wc -l | tr -d '[:space:]') INT_TESTS=$(grep "# Total tests" $OUTFILE | cut -c21- | tr -d '[:space:]') echo "Unit tests: ${UNIT_TESTS}" echo "Integration tests: ${INT_TESTS}" # These steps are from the README to verify it can be installed and run as # documented. go build export C2GO_DIR=$GOPATH/src/github.com/elliotchance/c2go export C2GO=$C2GO_DIR/c2go echo "Run: c2go transpile prime.c" $C2GO transpile -o=/tmp/prime.go $C2GO_DIR/examples/prime.c echo "47" | go run /tmp/prime.go if [ $($C2GO -v | wc -l) -ne 1 ]; then exit 1; fi if [ $(cat /tmp/prime.go | wc -l) -eq 0 ]; then exit 1; fi if [ $($C2GO ast $C2GO_DIR/examples/prime.c | wc -l) -eq 0 ]; then exit 1; fi echo "----------------------" # This will have to be updated every so often to the latest version. You can # find the latest version here: https://sqlite.org/download.html export SQLITE3_FILE=sqlite-amalgamation-3240000 # Variable for location of temp sqlite files SQLITE_TEMP_FOLDER="/tmp/SQLITE" mkdir -p $SQLITE_TEMP_FOLDER # Download/unpack SQLite if required. if [ ! -e $SQLITE_TEMP_FOLDER/$SQLITE3_FILE.zip ]; then curl https://sqlite.org/2018/$SQLITE3_FILE.zip > $SQLITE_TEMP_FOLDER/$SQLITE3_FILE.zip unzip $SQLITE_TEMP_FOLDER/$SQLITE3_FILE.zip -d $SQLITE_TEMP_FOLDER fi # Clean generated files. This should not be required, but it's polite. rm -f $SQLITE_TEMP_FOLDER/sqlite3.go $SQLITE_TEMP_FOLDER/shell.go # Transpile the SQLite3 files. # If transpiling write to stderr, then it will be append into OUTFILE # shell.c echo "Transpiling shell.c..." ./c2go transpile -o=$SQLITE_TEMP_FOLDER/shell.go $SQLITE_TEMP_FOLDER/$SQLITE3_FILE/shell.c >> $OUTFILE 2>&1 # sqlite3.c echo "Transpiling sqlite3.c..." ./c2go transpile -o=$SQLITE_TEMP_FOLDER/sqlite3.go $SQLITE_TEMP_FOLDER/$SQLITE3_FILE/sqlite3.c >> $OUTFILE 2>&1 # Show amount "Warning" in sqlite Go codes SQLITE_WARNINGS=`cat $SQLITE_TEMP_FOLDER/sqlite3.go $SQLITE_TEMP_FOLDER/shell.go | grep "// Warning" | wc -l` echo "In files (sqlite3.go and shell.go) summary : $SQLITE_WARNINGS warnings." # Update Github PR statuses. These two statuses will always pass but will show # information about the number of tests run and how many warnings are generated # in the SQLite3 transpile. if [ "$TRAVIS_OS_NAME" == "osx" ]; then curl -H "Authorization: token ${GITHUB_API_TOKEN}" -H "Content-Type: application/json" https://api.github.com/repos/elliotchance/c2go/statuses/${TRAVIS_COMMIT} -d "{\"state\": \"success\",\"target_url\": \"https://travis-ci.org/elliotchance/c2go/builds/${TRAVIS_JOB_ID}\", \"description\": \"$(($UNIT_TESTS + $INT_TESTS)) tests passed (${UNIT_TESTS} unit + ${INT_TESTS} integration)\", \"context\": \"c2go/tests\"}" curl -H "Authorization: token ${GITHUB_API_TOKEN}" -H "Content-Type: application/json" https://api.github.com/repos/elliotchance/c2go/statuses/${TRAVIS_COMMIT} -d "{\"state\": \"success\",\"target_url\": \"https://travis-ci.org/elliotchance/c2go/builds/${TRAVIS_JOB_ID}\", \"description\": \"$(($SQLITE_WARNINGS)) warnings\", \"context\": \"c2go/sqlite3\"}" fi # SQLITE c2go transpile -o="$SQLITE_TEMP_FOLDER/sqlite.go" -clang-flag="-DSQLITE_THREADSAFE=0" -clang-flag="-DSQLITE_OMIT_LOAD_EXTENSION" $SQLITE_TEMP_FOLDER/$SQLITE3_FILE/shell.c $SQLITE_TEMP_FOLDER/$SQLITE3_FILE/sqlite3.c # Show amount "Warning": SQLITE_WARNINGS=`cat $SQLITE_TEMP_FOLDER/sqlite.go | grep "// Warning" | wc -l` echo "After transpiling shell.c and sqlite3.c together, have summary: $SQLITE_WARNINGS warnings." # Show amount error from `go build`: SQLITE_WARNINGS_GO=`go build -gcflags="-e" $SQLITE_TEMP_FOLDER/sqlite.go 2>&1 | wc -l` echo "In file sqlite.go summary : $SQLITE_WARNINGS_GO warnings in go build." # Amount warning from gometalinter echo "Calculation warnings by gometalinter" GOMETALINTER_WARNINGS=`$GOPATH/bin/gometalinter $SQLITE_TEMP_FOLDER/sqlite.go 2>&1 | wc -l` echo "Amount found warnings by gometalinter at 30 second : $GOMETALINTER_WARNINGS warnings." c2go-0.26.10/types/000077500000000000000000000000001410601753200136555ustar00rootroot00000000000000c2go-0.26.10/types/binary_operator.go000066400000000000000000000006701410601753200174060ustar00rootroot00000000000000package types import ( "github.com/elliotchance/c2go/program" ) // ResolveTypeForBinaryOperator determines the result Go type when performing a // binary expression. func ResolveTypeForBinaryOperator(p *program.Program, operator, leftType, rightType string) string { if operator == "==" || operator == "!=" || operator == ">" || operator == ">=" || operator == "<" || operator == "<=" { return "bool" } return leftType } c2go-0.26.10/types/binary_operator_test.go000066400000000000000000000030631410601753200204440ustar00rootroot00000000000000package types import ( "fmt" "testing" "github.com/elliotchance/c2go/program" ) func TestResolveTypeForBinaryOperator(t *testing.T) { p := program.NewProgram() type args struct { operator string leftType string rightType string } tests := []struct { args args want string }{ // Bitwise {args{"|", "int", "int"}, "int"}, {args{"&", "int", "int"}, "int"}, {args{"<<", "int", "int"}, "int"}, {args{">>", "int", "int"}, "int"}, // Comparison {args{"==", "int", "int"}, "bool"}, {args{"==", "float", "int"}, "bool"}, {args{"!=", "int", "int"}, "bool"}, {args{"!=", "float", "int"}, "bool"}, {args{">", "int", "int"}, "bool"}, {args{">", "float", "int"}, "bool"}, {args{">=", "int", "int"}, "bool"}, {args{">=", "float", "int"}, "bool"}, {args{"<", "int", "int"}, "bool"}, {args{"<", "float", "int"}, "bool"}, {args{"<=", "int", "int"}, "bool"}, {args{"<=", "float", "int"}, "bool"}, // Arithmetic {args{"+", "int", "int"}, "int"}, {args{"+", "float", "float"}, "float"}, {args{"-", "int", "int"}, "int"}, {args{"-", "float", "float"}, "float"}, {args{"*", "int", "int"}, "int"}, {args{"*", "float", "float"}, "float"}, {args{"/", "int", "int"}, "int"}, {args{"/", "float", "float"}, "float"}, } for _, tt := range tests { name := fmt.Sprintf("%#v", tt.args) t.Run(name, func(t *testing.T) { if got := ResolveTypeForBinaryOperator(p, tt.args.operator, tt.args.leftType, tt.args.rightType); got != tt.want { t.Errorf("ResolveTypeForBinaryOperator() = %v, want %v", got, tt.want) } }) } } c2go-0.26.10/types/cast.go000066400000000000000000000365271410601753200151530ustar00rootroot00000000000000package types import ( "fmt" "go/token" "strings" goast "go/ast" "strconv" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/util" ) // GetArrayTypeAndSize returns the size and type of a fixed array. If the type // is not an array with a fixed size then the the size will be -1 and the // returned type should be ignored. func GetArrayTypeAndSize(s string) (string, int) { match := util.GetRegex(`([\w\* ]*)\[(\d+)\]((\[\d+\])*)`).FindStringSubmatch(s) if len(match) > 0 { var t = fmt.Sprintf("%s%s", match[1], match[3]) return strings.Trim(t, " "), util.Atoi(match[2]) } return s, -1 } // CastExpr returns an expression that casts one type to another. For // reliability and flexability the existing type (fromType) must be structly // provided. // // There are lots of rules about how an expression is cast, but here are some // main points: // // 1. If fromType == toType (casting to the same type) OR toType == "void *", // the original expression is returned unmodified. // // 2. There is a special type called "null" which is not defined in C, but // rather an estimate of the NULL macro which evaluates to: (0). We cannot // guarantee that original C used the NULL macro but it is a safe assumption // for now. // // The reason why NULL is special (or at least seamingly) is that it is often // used in different value contexts. As a number, testing pointers and // strings. Being able to better understand the original purpose of the code // helps to generate cleaner and more Go-like output. // // 3. There is a set of known primitive number types like "int", "float", etc. // These we know can be safely cast between each other by using the data type // as a function. For example, 3 (int) to a float would produce: // "float32(3)". // // There are also some platform specific types and types that are shared in // Go packages that are common aliases kept in this list. // // 4. If all else fails the fallback is to cast using a function. For example, // Foo -> Bar, would return an expression similar to "noarch.FooToBar(expr)". // This code would certainly fail with custom types, but that would likely be // a bug. It is most useful to do this when dealing with compound types like // FILE where those function probably exist (or should exist) in the noarch // package. func CastExpr(p *program.Program, expr goast.Expr, cFromType, cToType string) ( _ goast.Expr, err2 error) { defer func() { if err2 != nil { err2 = fmt.Errorf("Cannot casting {%s -> %s}. err = %v", cFromType, cToType, err2) } }() cFromType = CleanCType(cFromType) cToType = CleanCType(cToType) fromType := cFromType toType := cToType if cFromType == cToType { return expr, nil } if expr == nil { return nil, fmt.Errorf("Expr is nil") } // Function casting // Example : // cFromType : double (int, float, double) // cToType : double (*)(int, float, double) if IsFunction(cFromType) { if cToType == "void *" { p.AddImport("github.com/elliotchance/c2go/noarch") return util.NewCallExpr("noarch.CastInterfaceToPointer", expr), nil } return expr, nil } // Exceptions for stdout, stdin, stderr if fromType == "FILE *" && toType == "struct _IO_FILE *" { return expr, nil } if fromType == "struct _IO_FILE *" && toType == "FILE *" { return expr, nil } // Exception for va_list: // A pointer to struct __va_list_tag is always a variable called // "c2goVaList" in go. if fromType == "va_list" && toType == "struct __va_list_tag *" { ret := &goast.BasicLit{Kind: token.STRING, Value: "c2goVaList"} return ret, nil } // casting if fromType == "void *" && toType[len(toType)-1] == '*' && !strings.Contains(toType, "FILE") { toType, err := ResolveType(p, toType) if err != nil { return nil, err } return &goast.CallExpr{ Fun: &goast.ParenExpr{ X: util.NewTypeIdent(toType), }, Args: []goast.Expr{expr}, }, nil } // Checking amount recursive typedef element list := []string{fromType, toType} for _, l := range list { if v, ok := p.TypedefType[l]; ok { var typedefs []string for { if vv, ok := p.TypedefType[v]; ok { for i := range typedefs { if vv == typedefs[i] { return expr, fmt.Errorf("recursive typedef %s in : %v", vv, typedefs) } } v = vv typedefs = append(typedefs, vv) } else { break } } } } // Checking registered typedef types in program if v, ok := p.TypedefType[toType]; ok { if fromType == v { toType, err := ResolveType(p, toType) if err != nil { return expr, err } return &goast.CallExpr{ Fun: &goast.Ident{ Name: toType, }, Lparen: 1, Args: []goast.Expr{ &goast.ParenExpr{ Lparen: 1, X: expr, Rparen: 2, }, }, Rparen: 2, }, nil } e, err := CastExpr(p, expr, fromType, v) if err != nil { return nil, err } return CastExpr(p, e, v, toType) } if v, ok := p.TypedefType[fromType]; ok { t, err := ResolveType(p, v) if err != nil { return expr, err } expr = &goast.CallExpr{ Fun: &goast.Ident{ Name: t, }, Lparen: 1, Args: []goast.Expr{ &goast.ParenExpr{ Lparen: 1, X: expr, Rparen: 2, }, }, Rparen: 2, } if toType == v { return expr, nil } return CastExpr(p, expr, v, toType) } // C null pointer can cast to any pointer if cFromType == NullPointer && len(cToType) > 0 { if cToType[len(cToType)-1] == '*' { return expr, nil } } // Replace for specific case of fromType for darwin: // Fo : union (anonymous union at sqlite3.c:619241696:3) if strings.Contains(fromType, "anonymous union") { // I don't understood - How to change correctly // Try change to : `union` , but it is FAIL with that fromType = "" } // convert enum to int and recursive if strings.Contains(fromType, "enum") && !strings.Contains(toType, "enum") { in := goast.CallExpr{ Fun: &goast.Ident{ Name: "int32", }, Lparen: 1, Args: []goast.Expr{ &goast.ParenExpr{ Lparen: 1, X: expr, Rparen: 2, }, }, Rparen: 2, } return CastExpr(p, &in, "int", toType) } // convert int to enum and recursive if !strings.Contains(fromType, "enum") && strings.Contains(toType, "enum") { in := goast.CallExpr{ Fun: &goast.Ident{ Name: strings.TrimSpace(strings.Replace(toType, "enum", "", -1)), }, Lparen: 1, Args: []goast.Expr{ &goast.ParenExpr{ Lparen: 1, X: expr, Rparen: 2, }, }, Rparen: 2, } return CastExpr(p, &in, toType, toType) } fromType, err := ResolveType(p, fromType) if err != nil { return expr, err } toType, err = ResolveType(p, toType) if err != nil { return expr, err } if toType == fromType { return expr, nil } // Let's assume that anything can be converted to a void pointer. if cToType == "void *" { if strings.HasPrefix(fromType, "[]") { cNewFromType := string(util.GetRegex(`\[(\d+)\]$`).ReplaceAllLiteral([]byte(cFromType), []byte("*"))) if cNewFromType != cFromType { expr, err = CastExpr(p, expr, cFromType, cNewFromType) if err != nil { return expr, err } } } return util.NewCallExpr("unsafe.Pointer", expr), nil } if fromType == "null" && strings.HasPrefix(toType, "*") { return util.NewNil(), nil } if fromType == "null" && toType == "float64" { return util.NewFloatLit(0.0), nil } if fromType == "null" && toType == "bool" { return util.NewIdent("false"), nil } // FIXME: This is a hack to avoid casting in some situations. if fromType == "" || toType == "" { return expr, nil } if fromType == "null" && toType == "[]byte" { return util.NewNil(), nil } // This if for linux. if fromType == "*_IO_FILE" && toType == "*noarch.File" { return expr, nil } if strings.HasPrefix(fromType, "[]") && strings.HasPrefix(toType, "*") && fromType[2:] == toType[1:] { match := util.GetRegex(`\[(\d*)\]$`).FindStringSubmatch(cFromType) if strings.HasSuffix(cToType, "*") && len(match) > 0 { // we need to convert from array to pointer return &goast.UnaryExpr{ Op: token.AND, X: &goast.IndexExpr{ X: expr, Index: util.NewIntLit(0), }, }, nil } return expr, nil } // Compatible integer types types := []string{ // Integer types "byte", "int", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", // Floating-point types. "float32", "float64", // Known aliases "__uint16_t", "size_t", // Darwin specific "__darwin_ct_rune_t", "darwin.CtRuneT", } unsigned := map[string]bool{"byte": true, "uint8": true, "uint16": true, "uint32": true, "uint64": true, "__uint16_t": true, "size_t": true, "darwin_ct_rune_t": true, "darwin.CtRuneT": true} var isFromNumber, isFromUnsigned, isToNumber, isToUnsigned bool for _, v := range types { if fromType == v { isFromNumber = true if b, ok := unsigned[v]; ok && b { isFromUnsigned = true } } if toType == v { isToNumber = true if b, ok := unsigned[v]; ok && b { isToUnsigned = true } } if fromType == v && toType == "bool" { e := util.NewBinaryExpr( expr, token.NEQ, util.NewIntLit(0), toType, false, ) return e, nil } if fromType == "bool" && toType == v { e := util.NewGoExpr(`func(val bool) int32 { if val { return 1 } else { return 0 } }(replaceme)`) // Swap replaceme with the current expression e.(*goast.CallExpr).Args = []goast.Expr{expr} return CastExpr(p, e, "int", cToType) } } if isFromNumber && isToNumber && isToUnsigned && !isFromUnsigned { // To fix x overflows unsigned we swap cast and complement operator. if e, ok := expr.(*goast.UnaryExpr); ok && e.Op == token.XOR { c, err := CastExpr(p, e.X, cFromType, cToType) e.X = c return e, err } } // In the forms of: // - `string` -> `*byte` // - `string` -> `char *[13]` match1 := util.GetRegex(`\*byte`).FindStringSubmatch(toType) match2 := util.GetRegex(`char \*\[(\d+)\]`).FindStringSubmatch(toType) if fromType == "string" && (len(match1) > 0 || len(match2) > 0) { // Construct a byte array from "first": // // var str []byte = []byte{'f','i','r','s','t'} value := &goast.CompositeLit{ Type: &goast.ArrayType{ Elt: util.NewTypeIdent("byte"), }, Elts: []goast.Expr{}, } strValue, err := strconv.Unquote(expr.(*goast.BasicLit).Value) if err != nil { panic(fmt.Sprintf("Failed to Unquote %s\n", expr.(*goast.BasicLit).Value)) } for _, c := range []byte(strValue) { value.Elts = append(value.Elts, &goast.BasicLit{ Kind: token.CHAR, Value: fmt.Sprintf("%q", c), }) } value.Elts = append(value.Elts, util.NewIntLit(0)) return &goast.UnaryExpr{ Op: token.AND, X: &goast.IndexExpr{ X: value, Index: util.NewIntLit(0), }, }, nil } // In the forms of: // - `[7]byte` -> `string` // - `char *[12]` -> `string` match1 = util.GetRegex(`\[(\d+)\]byte`).FindStringSubmatch(fromType) match2 = util.GetRegex(`char \*\[(\d+)\]`).FindStringSubmatch(fromType) if (len(match1) > 0 || len(match2) > 0) && toType == "string" { size := 0 if len(match1) > 0 { size = util.Atoi(match1[1]) } else { size = util.Atoi(match2[1]) } // The following code builds this: // // string(expr[:size - 1]) // return util.NewCallExpr( "string", &goast.SliceExpr{ X: expr, High: util.NewIntLit(size - 1), }, ), nil } // Anything that is a pointer can be compared to nil if fromType[0] == '*' && toType == "bool" { e := util.NewBinaryExpr(expr, token.NEQ, util.NewNil(), toType, false) return e, nil } if fromType == "*byte" && toType == "bool" { return util.NewUnaryExpr( token.NOT, util.NewCallExpr("noarch.CStringIsNull", expr), ), nil } if fromType == "int" && toType == "*int" { return util.NewNil(), nil } if fromType == "int" && toType == "*byte" { return util.NewStringLit(`""`), nil } if fromType == "_Bool" && toType == "int" { return expr, nil } if util.InStrings(fromType, types) && util.InStrings(toType, types) { return util.NewCallExpr(toType, expr), nil } if strings.HasPrefix(toType, "*") && strings.HasPrefix(fromType, "*") { return &goast.CallExpr{ Fun: &goast.ParenExpr{ X: util.NewTypeIdent(toType), }, Args: []goast.Expr{ util.NewCallExpr("unsafe.Pointer", expr), }, }, nil } if strings.HasPrefix(toType, "[]") && strings.HasPrefix(fromType, "*") && isArrayToPointerExpr(expr) { expr = extractArrayFromPointer(expr) fromType = "[]" + fromType[1:] } leftName := fromType rightName := toType if strings.Contains(leftName, ".") { parts := strings.Split(leftName, ".") leftName = parts[len(parts)-1] } if strings.Contains(rightName, ".") { parts := strings.Split(rightName, ".") rightName = parts[len(parts)-1] } if cFromType == "void *" && cToType == "char *" { return expr, nil } if toType == fromType { return expr, nil } p.AddImport("github.com/elliotchance/c2go/noarch") p.AddImport("unsafe") exportedLeftName := util.GetExportedName(leftName) exportedRightName := util.GetExportedName(rightName) functionName := fmt.Sprintf("noarch.%sTo%s", exportedLeftName, exportedRightName) if strings.HasSuffix(exportedLeftName, "Slice") && strings.HasSuffix(exportedRightName, "Slice") { p.AddMessage(fmt.Sprintf("// Warning: using unsafe slice cast to convert from %s to %s", fromType, toType)) fromSize, err := SizeOf(p, GetBaseType(cFromType)) if err != nil { return nil, err } toSize, err := SizeOf(p, GetBaseType(cToType)) if err != nil { return nil, err } if _, arrSize := GetArrayTypeAndSize(cFromType); arrSize > 0 { expr = &goast.SliceExpr{X: expr} } return &goast.StarExpr{ X: &goast.CallExpr{ Fun: &goast.StarExpr{ X: &goast.Ident{ Name: toType, }, }, Lparen: 1, Args: []goast.Expr{ util.NewCallExpr("unsafe.Pointer", util.NewCallExpr("noarch.UnsafeSliceToSlice", expr, util.NewIntLit(fromSize), util.NewIntLit(toSize))), }, Rparen: 2, }, }, nil } // FIXME: This is a hack to get SQLite3 to transpile. if strings.Contains(functionName, "RowSetEntry") { functionName = "FIXME111" } return util.NewCallExpr(functionName, expr), nil } func isArrayToPointerExpr(expr goast.Expr) bool { if p1, ok := expr.(*goast.ParenExpr); ok { if p2, ok := p1.X.(*goast.UnaryExpr); ok && p2.Op == token.AND { if p3, ok := p2.X.(*goast.IndexExpr); ok { if p4, ok := p3.Index.(*goast.BasicLit); ok && p4.Kind == token.INT && p4.Value == "0" { return true } } } } return false } func extractArrayFromPointer(expr goast.Expr) goast.Expr { if p1, ok := expr.(*goast.ParenExpr); ok { if p2, ok := p1.X.(*goast.UnaryExpr); ok && p2.Op == token.AND { if p3, ok := p2.X.(*goast.IndexExpr); ok { return p3.X } } } return nil } // IsNullExpr tries to determine if the expression is the result of the NULL // macro. In C, NULL is actually a macro that produces an expression like "(0)". // // There are no guarantees if the original C code used the NULL macro, but it is // usually a pretty good guess when we see this specific exression signature. // // Either way the return value from IsNullExpr should not change the // functionality of the code but can lead to hints that allow the Go produced to // be cleaner and more Go-like. func IsNullExpr(n goast.Expr) bool { if p1, ok := n.(*goast.ParenExpr); ok { if p2, ok := p1.X.(*goast.BasicLit); ok && p2.Value == "0" { return true } } return false } c2go-0.26.10/types/cast_test.go000066400000000000000000000043661410601753200162060ustar00rootroot00000000000000package types import ( "encoding/json" "fmt" "reflect" "testing" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/util" goast "go/ast" "go/token" ) func toJSON(v interface{}) string { b, _ := json.MarshalIndent(v, "", " ") return string(b) } func TestCast(t *testing.T) { p := program.NewProgram() type args struct { expr goast.Expr fromType string toType string } tests := []struct { args args want goast.Expr }{ // Casting to the same type is not needed. {args{util.NewIntLit(1), "int", "int"}, util.NewIntLit(1)}, {args{util.NewFloatLit(2.3), "float", "float"}, util.NewFloatLit(2.3)}, // Casting between numeric types. {args{util.NewIntLit(1), "int", "float"}, util.NewCallExpr("float32", util.NewIntLit(1))}, {args{util.NewIntLit(1), "int", "double"}, util.NewCallExpr("float64", util.NewIntLit(1))}, {args{util.NewIntLit(1), "int", "__uint16_t"}, util.NewCallExpr("uint16", util.NewIntLit(1))}, // Casting to bool {args{util.NewIntLit(1), "int", "bool"}, util.NewBinaryExpr(util.NewIntLit(1), token.NEQ, util.NewIntLit(0), "bool", false)}, } for _, tt := range tests { name := fmt.Sprintf("%#v", tt.args) t.Run(name, func(t *testing.T) { got, err := CastExpr(p, tt.args.expr, tt.args.fromType, tt.args.toType) if err != nil { t.Error(err) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("Cast()%s\n", util.ShowDiff(toJSON(got), toJSON(tt.want))) } }) } } func TestGetArrayTypeAndSize(t *testing.T) { tests := []struct { in string cType string size int }{ {"int", "int", -1}, {"int [4]", "int", 4}, {"int [4][3]", "int [3]", 4}, {"int [4][3][2]", "int [3][2]", 4}, {"int [4][3][2][1]", "int [3][2][1]", 4}, {"int *[4]", "int *", 4}, {"int *[4][3]", "int *[3]", 4}, {"int *[4][3][2]", "int *[3][2]", 4}, {"int *[4][3][2][1]", "int *[3][2][1]", 4}, {"char *const", "char *const", -1}, {"char *const [6]", "char *const", 6}, {"char *const [6][5]", "char *const [5]", 6}, } for _, tt := range tests { cType, size := GetArrayTypeAndSize(tt.in) if cType != tt.cType { t.Errorf("Expected type '%s', got '%s'", tt.cType, cType) } if size != tt.size { t.Errorf("Expected size '%d', got '%d'", tt.size, size) } } } c2go-0.26.10/types/dereference.go000066400000000000000000000027001410601753200164520ustar00rootroot00000000000000package types import ( "errors" "fmt" "strings" "github.com/elliotchance/c2go/util" ) // IsDereferenceType - check is that type dereference func IsDereferenceType(cType string) bool { return strings.ContainsAny(cType, "[]*") } // GetDereferenceType returns the C type that would be the result of // dereferencing (unary "*" operator or accessing a single array element on a // pointer) a value. // // For example if the input type is "char *", then dereferencing or accessing a // single element would result in a "char". // // If the dereferenced type cannot be determined or is impossible ("char" cannot // be dereferenced, for example) then an error is returned. func GetDereferenceType(cType string) (_ string, err error) { defer func() { if err != nil { err = fmt.Errorf("Error in GetDereferenceType : %v", err) } }() // In the form of: "int [2][3][4]" -> "int [3][4]" search := util.GetRegex(`([\w\* ]+)\s*\[\d+\]((\[\d+\])+)`).FindStringSubmatch(cType) if len(search) > 0 { return search[1] + search[2], nil } // In the form of: "char [8]" -> "char" search = util.GetRegex(`([\w\* ]+)\s*\[\d+\]`).FindStringSubmatch(cType) if len(search) > 0 { return strings.TrimSpace(search[1]), nil } // In the form of: "char **" -> "char *" search = util.GetRegex(`([\w ]+)\s*(\*+)`).FindStringSubmatch(cType) if len(search) > 0 { return strings.TrimSpace(search[1] + search[2][0:len(search[2])-1]), nil } return "", errors.New(cType) } c2go-0.26.10/types/dereference_test.go000066400000000000000000000015621410601753200175160ustar00rootroot00000000000000package types import "testing" import "fmt" func TestGetDereferenceType(t *testing.T) { type args struct { cType string } tests := []struct { args args want string wantErr bool }{ {args{"char [8]"}, "char", false}, {args{"char**"}, "char*", false}, {args{"char *[8]"}, "char *", false}, {args{"char *[8][7]"}, "char *[7]", false}, {args{"char *[8][7][6]"}, "char *[7][6]", false}, {args{"char **[8]"}, "char **", false}, {args{"char ***[8]"}, "char ***", false}, } for _, tt := range tests { name := fmt.Sprintf("%#v", tt.args) t.Run(name, func(t *testing.T) { got, err := GetDereferenceType(tt.args.cType) if (err != nil) != tt.wantErr { t.Errorf("GetDereferenceType() error = %v, wantErr %v", err, tt.wantErr) return } if got != tt.want { t.Errorf("GetDereferenceType() = %v, want %v", got, tt.want) } }) } } c2go-0.26.10/types/resolve.go000066400000000000000000000453601410601753200156730ustar00rootroot00000000000000package types import ( "errors" "fmt" "regexp" "strconv" "strings" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/util" ) // cIntegerType - slice of C integer type var cIntegerType = []string{ "int", "long long", "long long int", "long long unsigned int", "long unsigned int", "long", "short", "unsigned int", "unsigned long long", "unsigned long", "unsigned short", "unsigned short int", } // IsCInteger - return true is C type integer func IsCInteger(p *program.Program, cType string) bool { for i := range cIntegerType { if cType == cIntegerType[i] { return true } } if rt, ok := p.TypedefType[cType]; ok { return IsCInteger(p, rt) } return false } // TODO: Some of these are based on assumptions that may not be true for all // architectures (like the size of an int). At some point in the future we will // need to find out the sizes of some of there and pick the most compatible // type. // // Please keep them sorted by name. var simpleResolveTypes = map[string]string{ "bool": "bool", "char *": "*byte", "char": "byte", "char*": "*byte", "double": "float64", "float": "float32", "int": "int32", "long double": "float64", "long int": "int32", "long long": "int64", "long long int": "int64", "long long unsigned int": "uint64", "long unsigned int": "uint32", "long": "int32", "ptrdiff_t": "int32", "short": "int16", "signed char": "int8", "size_t": "uint32", "uintptr_t": "uintptr", "unsigned char": "uint8", "unsigned int": "uint32", "unsigned long long": "uint64", "unsigned long": "uint32", "unsigned short": "uint16", "unsigned short int": "uint16", "void": "", "wchar_t": "rune", "_Bool": "int8", // void* "void*": "unsafe.Pointer", "void *": "unsafe.Pointer", // null is a special case (it should probably have a less ambiguous name) // when using the NULL macro. "null": "null", // Non platform-specific types. "int8": "int8", "int8_t": "int8", "int16": "int16", "int16_t": "int16", "int32": "int32", "int32_t": "int32", "int64": "int64", "int64_t": "int64", "uint8": "uint8", "uint8_t": "uint8", "uint16": "uint16", "uint16_t": "uint16", "uint32": "uint32", "uint32_t": "uint32", "uint64": "uint64", "uint64_t": "uint64", "u_int8_t": "uint8", "u_int16_t": "uint16", "u_int32_t": "uint32", "u_int64_t": "uint64", "__int8_t": "int8", "__int16_t": "int16", "__int32_t": "int32", "__int64_t": "int64", "__uint8_t": "uint8", "__uint16_t": "uint16", "__uint32_t": "uint32", "__uint64_t": "uint64", // These are special cases that almost certainly don't work. I've put // them here because for whatever reason there is no suitable type or we // don't need these platform specific things to be implemented yet. "__builtin_va_list": "int64", "__darwin_pthread_handler_rec": "int64", "unsigned __int128": "uint64", "__int128": "int64", "__mbstate_t": "int64", "__sbuf": "int64", "__sFILEX": "unsafe.Pointer", "FILE": "github.com/elliotchance/c2go/noarch.File", } var otherStructType = map[string]string{ "div_t": "github.com/elliotchance/c2go/noarch.DivT", "ldiv_t": "github.com/elliotchance/c2go/noarch.LdivT", "lldiv_t": "github.com/elliotchance/c2go/noarch.LldivT", // time.h "tm": "github.com/elliotchance/c2go/noarch.Tm", "struct tm": "github.com/elliotchance/c2go/noarch.Tm", "time_t": "github.com/elliotchance/c2go/noarch.TimeT", // Darwin specific "__darwin_ct_rune_t": "github.com/elliotchance/c2go/darwin.CtRuneT", "fpos_t": "int32", "struct __float2": "github.com/elliotchance/c2go/darwin.Float2", "struct __double2": "github.com/elliotchance/c2go/darwin.Double2", "Float2": "github.com/elliotchance/c2go/darwin.Float2", "Double2": "github.com/elliotchance/c2go/darwin.Double2", "struct __va_list_tag *": "github.com/elliotchance/c2go/noarch.VaList", } // NullPointer - is look : (double *)(nil) or (FILE *)(nil) // created only for transpiler.CStyleCastExpr var NullPointer = "NullPointerType *" // ToVoid - specific type for ignore the cast var ToVoid = "ToVoid" // ResolveType determines the Go type from a C type. // // Some basic examples are obvious, such as "float" in C would be "float32" in // Go. But there are also much more complicated examples, such as compound types // (structs and unions) and function pointers. // // Some general rules: // // 1. The Go type must be deterministic. The same C type will ALWAYS return the // same Go type, in any condition. This is extremely important since the // nature of C is that is may not have certain information available about the // rest of the program or libraries when it is being compiled. // // 2. Many C type modifiers and properties are lost as they have no sensible or // valid translation to Go. Some example of those would be "const" and // "volatile". It is left be up to the clang (or other compiler) to warn if // types are being abused against the standards in which they are being // compiled under. Go will make no assumptions about how you expect it act, // only how it is used. // // 3. New types are registered (discovered) throughout the transpiling of the // program, so not all types are know at any given time. This works exactly // the same way in a C compiler that will not let you use a type before it // has been defined. // // 4. If all else fails an error is returned. However, a type (which is almost // certainly incorrect) "interface{}" is also returned. This is to allow the // transpiler to step over type errors and put something as a placeholder // until a more suitable solution is found for those cases. func ResolveType(p *program.Program, s string) (_ string, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot resolve type '%s' : %v", s, err) } }() s = CleanCType(s) if s == "_Bool" { p.TypedefType[s] = "signed char" } // FIXME: This is a hack to avoid casting in some situations. if s == "" { return "unsafe.Pointer", errors.New("probably an incorrect type translation 1") } // FIXME: I have no idea what this is. if s == "const" { return "unsafe.Pointer", errors.New("probably an incorrect type translation 4") } if s == "char *[]" { return "unsafe.Pointer", errors.New("probably an incorrect type translation 2") } if s == "fpos_t" { return ResolveType(p, "int") } // FIXME: I have no idea, how to solve. // See : https://github.com/elliotchance/c2go/issues/628 if strings.Contains(s, "__locale_data") { s = strings.Replace(s, "struct __locale_data", "int", -1) s = strings.Replace(s, "__locale_data", "int", -1) } if strings.Contains(s, "__locale_struct") { return ResolveType(p, "int") } // function type is pointer in Go by default if len(s) > 2 { base := s[:len(s)-2] if ff, ok := p.TypedefType[base]; ok { if IsFunction(ff) { return base, nil } } } // The simple resolve types are the types that we know there is an exact Go // equivalent. For example float, int, etc. if v, ok := simpleResolveTypes[s]; ok { return p.ImportType(v), nil } // No need resolve typedef types if ss, ok := p.TypedefType[s]; ok { if tt, ok := otherStructType[s]; ok { // "div_t": "github.com/elliotchance/c2go/noarch.DivT", ii := p.ImportType(tt) return ii, nil } if s == "_Bool" { return ResolveType(p, ss) } return s, nil } if tt, ok := otherStructType[s]; ok { // "div_t": "github.com/elliotchance/c2go/noarch.DivT", ii := p.ImportType(tt) return ii, nil } // Try resolving correct type (covers anonymous structs/unions) correctType := GenerateCorrectType(s) if correctType != s { if res, err := ResolveType(p, correctType); err == nil { return res, nil } } // For function if IsFunction(s) { g, e := resolveFunction(p, s) return g, e } // Check is it typedef enum if _, ok := p.EnumTypedefName[s]; ok { return ResolveType(p, "int") } if v, ok := p.TypedefType[s]; ok { if IsFunction(v) { // typedef function return s, nil } return ResolveType(p, v) } // If the type is already defined we can proceed with the same name. if p.IsTypeAlreadyDefined(s) { return p.ImportType(s), nil } if _, ok := p.Structs["struct "+s]; ok { return p.ImportType(s), nil } if _, ok := p.Unions["union "+s]; ok { return p.ImportType(s), nil } // Structures are by name. if strings.HasPrefix(s, "struct ") || strings.HasPrefix(s, "union ") { start := 6 if s[0] == 's' { start++ } if s[len(s)-1] == '*' { s = s[start : len(s)-2] var t string t, err = ResolveType(p, s) return "*" + t, err } s = s[start:] for _, v := range simpleResolveTypes { if v == s { return p.ImportType(simpleResolveTypes[s]), nil } } return ResolveType(p, s) } // Enums are by name. if strings.HasPrefix(s, "enum ") { if s[len(s)-1] == '*' { return "*" + s[5:len(s)-2], nil } return s[5:], nil } // I have no idea how to handle this yet. if strings.Contains(s, "anonymous union") { return "unsafe.Pointer", errors.New("probably an incorrect type translation 3") } // It may be a pointer of a simple type. For example, float *, int *, // etc. if util.GetRegex("[\\w ]+\\*+$").MatchString(s) { // The "-1" is important because there may or may not be a space between // the name and the "*". If there is an extra space it will be trimmed // off. t, err := ResolveType(p, strings.TrimSpace(s[:len(s)-1])) // Pointers are always converted into slices, except with some specific // entities that are shared in the Go libraries. prefix := "*" return prefix + t, err } // Function pointers are not yet supported. In the mean time they will be // replaced with a type that certainly wont work until we can fix this // properly. search := util.GetRegex("[\\w ]+\\(\\*.*?\\)\\(.*\\)").MatchString(s) if search { return "interface{}", fmt.Errorf("function pointers are not supported [1] : '%s'", s) } search = util.GetRegex("[\\w ]+ \\(.*\\)").MatchString(s) if search { return "interface{}", fmt.Errorf("function pointers are not supported [2] : '%s'", s) } // It could be an array of fixed length. These needs to be converted to // slices. // int [2][3] -> [][]int // int [2][3][4] -> [][][]int search2 := util.GetRegex(`([\w\* ]+)((\[\d+\])+)`).FindStringSubmatch(s) if len(search2) > 2 { t, err := ResolveType(p, search2[1]) var re = util.GetRegex(`[0-9]+`) arraysNoSize := re.ReplaceAllString(search2[2], "") return fmt.Sprintf("%s%s", arraysNoSize, t), err } errMsg := fmt.Sprintf( "I couldn't find an appropriate Go type for the C type '%s'.", s) return "unsafe.Pointer", errors.New(errMsg) } // resolveType determines the Go type from a C type. func resolveFunction(p *program.Program, s string) (goType string, err error) { var f, r []string f, r, err = SeparateFunction(p, s) goType = "func(" for i := range f { goType += fmt.Sprintf("%s", f[i]) if i < len(f)-1 { goType += " , " } } goType += ")(" for i := range r { goType += fmt.Sprintf("%s", r[i]) if i < len(r)-1 { goType += " , " } } goType += ")" return } // SeparateFunction separate a function C type to Go types parts. func SeparateFunction(p *program.Program, s string) ( fields []string, returns []string, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot separate function '%s' : %v", s, err) } }() f, r, err := ParseFunction(s) if err != nil { return } for i := range f { var t string t, err = ResolveType(p, f[i]) if err != nil { return } fields = append(fields, t) } for i := range r { var t string t, err = ResolveType(p, r[i]) if err != nil { return } returns = append(returns, t) } return } // IsFunction - return true if string is function like "void (*)(void)" func IsFunction(s string) bool { s = strings.Replace(s, "(*)", "", -1) return strings.Contains(s, "(") } // IsPointer - check type is pointer func IsPointer(p *program.Program, s string) bool { if strings.ContainsAny(s, "*[]") { return true } if v, ok := p.TypedefType[s]; ok { return IsPointer(p, v) } return false } // IsPurePointer - check type is pointer func IsPurePointer(p *program.Program, s string) bool { if strings.ContainsAny(s, "*") { return true } if v, ok := p.TypedefType[s]; ok { return IsPurePointer(p, v) } return false } // IsLastArray - check type have array '[]' func IsLastArray(s string) bool { for _, b := range s { switch b { case '[': return true case '*': break } } return false } // IsTypedefFunction - return true if that type is typedef of function. func IsTypedefFunction(p *program.Program, s string) bool { if v, ok := p.TypedefType[s]; ok && IsFunction(v) { return true } s = string(s[0 : len(s)-len(" *")]) if v, ok := p.TypedefType[s]; ok && IsFunction(v) { return true } return false } // ParseFunction - parsing elements of C function func ParseFunction(s string) (f []string, r []string, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot parse function '%s' : %v", s, err) } }() s = strings.TrimSpace(s) if !IsFunction(s) { err = fmt.Errorf("Is not function : %s", s) return } var arguments string { // Example of function types : // int (*)(int, float) // int (int, float) // int (*)(int (*)(int)) // void (*(*)(int *, void *, const char *))(void) if s[len(s)-1] != ')' { err = fmt.Errorf("function type |%s| haven't last symbol ')'", s) return } counter := 1 var pos int for i := len(s) - 2; i >= 0; i-- { if i == 0 { err = fmt.Errorf("Don't found '(' in type : %s", s) return } if s[i] == ')' { counter++ } if s[i] == '(' { counter-- } if counter == 0 { pos = i break } } r = append(r, strings.Replace(s[:pos], "(*)", "", -1)) arguments = s[pos:] } arguments = strings.TrimSpace(arguments) if arguments == "" { err = fmt.Errorf("Cannot parse (right part is nil) : %v", s) return } // separate fields of arguments { var pos int = 1 counter := 0 for i := 1; i < len(arguments)-1; i++ { if arguments[i] == '(' { counter++ } if arguments[i] == ')' { counter-- } if counter == 0 && arguments[i] == ',' { f = append(f, strings.TrimSpace(arguments[pos:i])) pos = i + 1 } } f = append(f, strings.TrimSpace(arguments[pos:len(arguments)-1])) } for i := range r { r[i] = strings.TrimSpace(r[i]) } for i := range f { f[i] = strings.TrimSpace(f[i]) } return } var ( rxconst = regexp.MustCompile(`\bconst\b`) rxvolatile = regexp.MustCompile(`\bvolatile\b`) rxUUrestrict = regexp.MustCompile(`\b__restrict\b`) rxrestrict = regexp.MustCompile(`\brestrict\b`) ) // CleanCType - remove from C type not Go type func CleanCType(s string) (out string) { out = s // remove space from pointer symbols out = strings.Replace(out, "* *", "**", -1) // add space for simplification redactoring out = strings.Replace(out, "*", " *", -1) out = strings.Replace(out, "( *)", "(*)", -1) // Remove any whitespace or attributes that are not relevant to Go. out = rxconst.ReplaceAllLiteralString(out, "") out = rxvolatile.ReplaceAllLiteralString(out, "") out = rxUUrestrict.ReplaceAllLiteralString(out, "") out = rxrestrict.ReplaceAllLiteralString(out, "") out = strings.Replace(out, "\t", "", -1) out = strings.Replace(out, "\n", "", -1) out = strings.Replace(out, "\r", "", -1) // remove space from pointer symbols out = strings.Replace(out, "* *", "**", -1) out = strings.Replace(out, "[", " [", -1) out = strings.Replace(out, "] [", "][", -1) // remove addition spaces out = strings.Replace(out, " ", " ", -1) // remove spaces around out = strings.TrimSpace(out) if out != s { return CleanCType(out) } return out } // GenerateCorrectType - generate correct type // Example: 'union (anonymous union at tests/union.c:46:3)' func GenerateCorrectType(name string) string { if !strings.Contains(name, "anonymous") { return name } index := strings.Index(name, "(anonymous") if index < 0 { return name } name = strings.Replace(name, "anonymous", "", 1) var last int for last = index; last < len(name); last++ { if name[last] == ')' { break } } // Create a string, for example: // Input (name) : 'union (anonymous union at tests/union.c:46:3)' // Output(inside) : '(anonymous union at tests/union.c:46:3)' inside := string(([]byte(name))[index : last+1]) // change unacceptable C name letters inside = strings.Replace(inside, "(", "B", -1) inside = strings.Replace(inside, ")", "E", -1) inside = strings.Replace(inside, " ", "S", -1) inside = strings.Replace(inside, ":", "D", -1) inside = strings.Replace(inside, "/", "S", -1) inside = strings.Replace(inside, "-", "T", -1) inside = strings.Replace(inside, "\\", "S", -1) inside = strings.Replace(inside, ".", "P", -1) out := string(([]byte(name))[0:index]) + inside + string(([]byte(name))[last+1:]) // For case: // struct siginfo_t::(anonymous at /usr/include/x86_64-linux-gnu/bits/siginfo.h:119:2) // we see '::' before 'anonymous' word out = strings.Replace(out, ":", "D", -1) return CleanCType(out) } // GetAmountArraySize - return amount array size // Example : // In : 'char [40]' // Out : 40 func GetAmountArraySize(cType string) (size int, err error) { reg := util.GetRegex("\\[(?P\\d+)\\]") match := reg.FindStringSubmatch(cType) if reg.NumSubexp() != 1 { err = fmt.Errorf("Cannot found size of array in type : %s", cType) return } result := make(map[string]string) for i, name := range reg.SubexpNames() { if i != 0 { result[name] = match[i] } } return strconv.Atoi(result["size"]) } // GetBaseType - return base type without pointera, array symbols // Input: // s = struct BSstructSatSShomeSlepriconSgoSsrcSgithubPcomSelliotchanceSc2goStestsSstructPcD260D18E [7] func GetBaseType(s string) string { s = strings.TrimSpace(s) s = CleanCType(s) if s[len(s)-1] == ']' { for i := len(s) - 1; i >= 0; i-- { if s[i] == '[' { s = s[:i] return GetBaseType(s) } } } if s[len(s)-1] == '*' { return GetBaseType(s[:len(s)-1]) } return s } // goIntegerType - slice of Go integer type var goIntegerType = []string{ "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", } // IsGoIntegerType - return whether the given Go type is an integer type func IsGoIntegerType(s string) bool { for _, i := range goIntegerType { if i == s { return true } } return false } c2go-0.26.10/types/resolve_test.go000066400000000000000000000121311410601753200167200ustar00rootroot00000000000000package types_test import ( "encoding/json" "fmt" "testing" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" ) type resolveTestCase struct { cType string goType string } var resolveTestCases = []resolveTestCase{ {"int", "int32"}, {"bool", "bool"}, {"_Bool", "int8"}, {"char", "byte"}, {"char *[13]", "[]*byte"}, {"__uint16_t", "uint16"}, {"void *", "unsafe.Pointer"}, {"unsigned short int", "uint16"}, {"div_t", "noarch.DivT"}, {"ldiv_t", "noarch.LdivT"}, {"lldiv_t", "noarch.LldivT"}, {"fpos_t", "int32"}, {"int [2]", "[]int32"}, {"int [2][3]", "[][]int32"}, {"int [2][3][4]", "[][][]int32"}, {"int [2][3][4][5]", "[][][][]int32"}, } func TestResolve(t *testing.T) { p := program.NewProgram() for i, testCase := range resolveTestCases { t.Run(fmt.Sprintf("Test %d : %s", i, testCase.cType), func(t *testing.T) { goType, err := types.ResolveType(p, testCase.cType) if err != nil { t.Fatal(err) } if goType != testCase.goType { t.Errorf("Expected '%s' -> '%s', got '%s'", testCase.cType, testCase.goType, goType) } }) } } func TestResolveFunction(t *testing.T) { var tcs = []struct { input string fields []string returns []string }{ { input: " void (*)(void)", fields: []string{"void"}, returns: []string{"void"}, }, { input: " int (*)(sqlite3_file *)", fields: []string{"sqlite3_file *"}, returns: []string{"int"}, }, { input: " int (*)(int)", fields: []string{"int"}, returns: []string{"int"}, }, { input: " int (*)(void *) ", fields: []string{"void *"}, returns: []string{"int"}, }, { input: " void (*)(sqlite3_context *, int, sqlite3_value **)", fields: []string{"sqlite3_context *", "int", "sqlite3_value **"}, returns: []string{"void"}, }, { input: "char *(*)( char *, ...)", fields: []string{"char *", "..."}, returns: []string{"char *"}, }, { input: "char *(*)( char *, struct __va_list_tag *)", fields: []string{"char *", "struct __va_list_tag *"}, returns: []string{"char *"}, }, { input: "char *(*)(const char *, ...)", fields: []string{"const char *", "..."}, returns: []string{"char *"}, }, { input: "char *(*)(ImportCtx *)", fields: []string{"ImportCtx *"}, returns: []string{"char *"}, }, { input: "char *(*)(int, char *, char *, ...)", fields: []string{"int", "char *", "char *", "..."}, returns: []string{"char *"}, }, { input: "const char *(*)(int)", fields: []string{"int"}, returns: []string{"const char *"}, }, { input: "const unsigned char *(*)(sqlite3_value *)", fields: []string{"sqlite3_value *"}, returns: []string{"const unsigned char *"}, }, { input: "int (*)(const char *, sqlite3 **)", fields: []string{"const char *", "sqlite3 **"}, returns: []string{"int"}, }, { input: "int (*)(fts5_api *, const char *, void *, fts5_extension_function, void (*)(void *))", fields: []string{"fts5_api *", "const char *", "void *", "fts5_extension_function", "void (*)(void *)"}, returns: []string{"int"}, }, { input: "int (*)(Fts5Context *, char *, int, void *, int (*)(void *, int, char *, int, int, int))", fields: []string{"Fts5Context *", "char *", "int", "void *", "int (*)(void *, int, char *, int, int, int)"}, returns: []string{"int"}, }, { input: "int (*)(sqlite3 *, char *, int, int, void *, void (*)(sqlite3_context *, int, sqlite3_value **), void (*)(sqlite3_context *, int, sqlite3_value **), void (*)(sqlite3_context *))", fields: []string{ "sqlite3 *", "char *", "int", "int", "void *", "void (*)(sqlite3_context *, int, sqlite3_value **)", "void (*)(sqlite3_context *, int, sqlite3_value **)", "void (*)(sqlite3_context *)", }, returns: []string{"int"}, }, /* { input: "int (*)(sqlite3_vtab *, int, const char *, void (**)(sqlite3_context *, int, sqlite3_value **), void **)", fields: []string{ "sqlite3_vtab *", "int", "const char *", "void (**)(sqlite3_context *, int, sqlite3_value **)", "void **"}, returns: []string{"int"}, },*/ } for i, tc := range tcs { t.Run(fmt.Sprintf("Test %d : %s", i, tc.input), func(t *testing.T) { actualField, actualReturn, err := types.ParseFunction(tc.input) if err != nil { t.Fatal(err) } if len(actualField) != len(tc.fields) { t.Error("Amount of fields is different") } if len(actualField) != len(tc.fields) { a, _ := json.Marshal(actualField) f, _ := json.Marshal(tc.fields) t.Errorf("Size of field is not same.\nActual : %s\nExpected: %s\n", string(a), string(f)) return } for i := range actualField { if actualField[i] != tc.fields[i] { t.Errorf("Not correct field: %v\nExpected: %v", actualField, tc.fields) } } if len(actualReturn) != len(tc.returns) { t.Error("Amount of return elements are different") } for i := range actualReturn { if actualReturn[i] != tc.returns[i] { t.Errorf("Not correct returns: %v\nExpected: %v", actualReturn, tc.returns) } } }) } } c2go-0.26.10/types/sizeof.go000066400000000000000000000065041410601753200155100ustar00rootroot00000000000000package types import ( "fmt" "strings" "github.com/elliotchance/c2go/program" ) // SizeOf returns the number of bytes for a type. This the same as using the // sizeof operator/function in C. func SizeOf(p *program.Program, cType string) (size int, err error) { defer func() { if err != nil { err = fmt.Errorf("Cannot determine sizeof : |%s|. err = %v", cType, err) } }() // Remove keywords that do not effect the size. cType = CleanCType(cType) cType = strings.Replace(cType, "unsigned ", "", -1) cType = strings.Replace(cType, "signed ", "", -1) // FIXME: The pointer size will be different on different platforms. We // should find out the correct size at runtime. pointerSize := 8 // Enum with name if strings.HasPrefix(cType, "enum") { return SizeOf(p, "int") } // typedef int Integer; if v, ok := p.TypedefType[cType]; ok { return SizeOf(p, v) } // typedef Enum if _, ok := p.EnumTypedefName[cType]; ok { return SizeOf(p, "int") } // A structure will be the sum of its parts. var isStruct, ok bool var s *program.Struct cType = GenerateCorrectType(cType) if s, ok = p.Structs[cType]; ok { isStruct = true } else if s, ok = p.Structs["struct "+cType]; ok { isStruct = true } if isStruct { totalBytes := 0 for _, t := range s.Fields { var bytes int var err error switch f := t.(type) { case string: bytes, err = SizeOf(p, f) case *program.Struct: bytes, err = SizeOf(p, f.Name) } if err != nil { return 0, err } totalBytes += bytes } // The size of a struct is rounded up to fit the size of the pointer of // the OS. if totalBytes < 32 && totalBytes%pointerSize != 0 { totalBytes += pointerSize - (totalBytes % pointerSize) } return totalBytes, nil } // An union will be the max size of its parts. if strings.HasPrefix(cType, "union ") { byteCount := 0 s := p.Unions[cType] if s == nil { return 0, fmt.Errorf("error in union") } for _, t := range s.Fields { var bytes int var err error switch f := t.(type) { case string: bytes, err = SizeOf(p, f) case *program.Struct: bytes, err = SizeOf(p, f.Name) } if err != nil { return 0, err } if byteCount < bytes { byteCount = bytes } } // The size of an union is rounded up to fit the size of the pointer of // the OS. if byteCount < 32 && byteCount%pointerSize != 0 { byteCount += pointerSize - (byteCount % pointerSize) } return byteCount, nil } // Function pointers are one byte? if strings.Contains(cType, "(") { return 1, nil } if strings.HasSuffix(cType, "*") { return pointerSize, nil } switch cType { case "char", "void", "bool": return 1, nil case "short": return 2, nil case "int", "float": return 4, nil case "long", "double": return 8, nil case "long double", "long long", "long long int", "long long unsigned int": return 16, nil } // Get size for array types like: `base_type [count]` totalArraySize := 1 arrayType, arraySize := GetArrayTypeAndSize(cType) if arraySize <= 0 { return 0, fmt.Errorf("error in array size") } for arraySize != -1 { totalArraySize *= arraySize arrayType, arraySize = GetArrayTypeAndSize(arrayType) } baseSize, err := SizeOf(p, arrayType) if err != nil { return 0, fmt.Errorf("error in sizeof baseSize") } return baseSize * totalArraySize, nil } c2go-0.26.10/types/sizeof_test.go000066400000000000000000000021671410601753200165500ustar00rootroot00000000000000package types_test import ( "fmt" "testing" "github.com/elliotchance/c2go/program" "github.com/elliotchance/c2go/types" ) type sizeofTestCase struct { cType string size int err error } var sizeofTestCases = []sizeofTestCase{ {"bool", 1, nil}, {"_Bool", 1, nil}, {"char", 1, nil}, {"int", 4, nil}, {"int [2]", 4 * 2, nil}, {"int [2][3]", 4 * 2 * 3, nil}, {"int [2][3][4]", 4 * 2 * 3 * 4, nil}, {"int *[2]", 8 * 2, nil}, {"int *[2][3]", 8 * 2 * 3, nil}, {"int *[2][3][4]", 8 * 2 * 3 * 4, nil}, {"int *", 8, nil}, {"int **", 8, nil}, {"int ***", 8, nil}, {"char *const", 8, nil}, {"char *const [3]", 24, nil}, {"struct c [2]", 0, fmt.Errorf("Cannot determine sizeof : |struct c [2]|. err = error in sizeof baseSize")}, } func TestSizeOf(t *testing.T) { p := program.NewProgram() for _, testCase := range sizeofTestCases { size, err := types.SizeOf(p, testCase.cType) if err != nil && (testCase.err == nil || (err.Error() != testCase.err.Error())) { t.Error(err) continue } if size != testCase.size { t.Errorf("Expected '%s' -> '%d', got '%d'", testCase.cType, testCase.size, size) } } } c2go-0.26.10/util/000077500000000000000000000000001410601753200134665ustar00rootroot00000000000000c2go-0.26.10/util/errors.go000066400000000000000000000010121410601753200153230ustar00rootroot00000000000000package util import "fmt" // PanicIfNil will panic with the message provided if the check is nil. This is // a convieniance method to avoid many similar if statements. func PanicIfNil(check interface{}, message string) { if check == nil { panic(message) } } // PanicOnError will panic with the message and error if the error is not nil. // If the error is nil (no error) then nothing happens. func PanicOnError(err error, message string) { if err != nil { panic(fmt.Sprintf("%s: %s", message, err.Error())) } } c2go-0.26.10/util/evaluate.go000066400000000000000000000033311410601753200156230ustar00rootroot00000000000000package util import ( goast "go/ast" "go/token" "strconv" ) // EvaluateConstExpr evaluates the given expression. // Returns whether the expr is an integer constant, // and the resulting number if constant. func EvaluateConstExpr(expr goast.Expr) (isConst bool, value int64) { calc := &calcVisitor{ isConst: true, } result := calc.Visit(expr) return calc.isConst, result } type calcVisitor struct { isConst bool } func (v *calcVisitor) Visit(node goast.Node) int64 { if node == nil { return 0 } if be, ok := node.(*goast.BinaryExpr); ok { x := v.Visit(be.X) y := v.Visit(be.Y) switch be.Op { case token.ADD: return x + y case token.SUB: return x - y case token.MUL: return x * y case token.QUO: if y == 0 { v.isConst = false return 0 } return x / y case token.REM: if y == 0 { v.isConst = false return 0 } return x % y case token.AND: return x & y case token.OR: return x | y case token.XOR: return x ^ y case token.SHL: return x << uint64(y) case token.SHR: return x >> uint64(y) case token.AND_NOT: return x &^ y } } if ue, ok := node.(*goast.UnaryExpr); ok { x := v.Visit(ue.X) switch ue.Op { case token.ADD: return x case token.SUB: return -x case token.XOR: return ^x } } if ce, ok := node.(*goast.CallExpr); ok { if fn, ok2 := ce.Fun.(*goast.Ident); !ok2 || fn.Name != "int32" { v.isConst = false return 0 } return v.Visit(ce.Args[0]) } if pe, ok := node.(*goast.ParenExpr); ok { return v.Visit(pe.X) } if ie, ok := node.(*goast.BasicLit); ok { if ie.Kind == token.INT { ret, err := strconv.Atoi(ie.Value) if err == nil { return int64(ret) } } } v.isConst = false return 0 } c2go-0.26.10/util/goast.go000066400000000000000000000312341410601753200151350ustar00rootroot00000000000000// This file contains utility and helper methods for making it easier to // generate parts of the Go AST. package util import ( "bytes" "fmt" goast "go/ast" "go/parser" "go/token" "strconv" "strings" ) // NewExprStmt returns a new ExprStmt from an expression. It is used when // converting a single expression into a statement for another receiver. // // It is recommended you use this method of instantiating the ExprStmt yourself // because NewExprStmt will check that the expr is not nil (or panic). This is // much more helpful when trying to debug why the Go source build crashes // because of a nil pointer - which eventually leads back to a nil expr. func NewExprStmt(expr goast.Expr) *goast.ExprStmt { PanicIfNil(expr, "expr is nil") return &goast.ExprStmt{ X: expr, } } // IsAValidFunctionName performs a check to see if a string would make a // valid function name in Go. Go allows unicode characters, but C doesn't. func IsAValidFunctionName(s string) bool { return GetRegex(`^[a-zA-Z_][a-zA-Z0-9_]*$`). Match([]byte(s)) } // Convert a type as a string into a Go AST expression. func typeToExpr(t string) goast.Expr { defer func() { if r := recover(); r != nil { panic(fmt.Sprintf("bad type: '%v'", t)) } }() return internalTypeToExpr(t) } func internalTypeToExpr(goType string) goast.Expr { // I'm not sure if this is an error or not. It is caused by processing the // resolved type of "void" which is "". It is used on functions to denote // that it does not have a return type. if goType == "" { return nil } separator := make([]bool, len(goType)+1) for i := range goType { switch goType[i] { case '.', '*', '(', ')', '-', '+', '&', '{', '}', ' ', '[', ']': separator[i] = true separator[i+1] = true } } // Specific case for 'interface{}' // remove all separator inside that word specials := [][]byte{[]byte("func("), []byte("interface{}")} for _, special := range specials { input := []byte(goType) again: index := bytes.Index(input, special) if index >= 0 { for i := index + 1; i < index+len(special); i++ { separator[i] = false } input = input[index+len(special)-1:] goto again } } separator[0] = true separator[len(separator)-1] = true // Separation string 'goType' to slice of bytes var indexes []int for i := range separator { if separator[i] { indexes = append(indexes, i) } } var lines [][]byte for i := 0; i < len(indexes)-1; i++ { lines = append(lines, []byte(goType[indexes[i]:indexes[i+1]])) } // Checking for i := range lines { if IsGoKeyword(string(lines[i])) { lines[i] = []byte(string(lines[i]) + "_") } } goType = string(bytes.Join(lines, []byte(""))) return goast.NewIdent(goType) } // NewCallExpr creates a new *"go/ast".CallExpr with each of the arguments // (after the function name) being each of the expressions that represent the // individual arguments. // // The function name is checked with IsAValidFunctionName and will panic if the // function name is deemed to be not valid. func NewCallExpr(functionName string, args ...goast.Expr) *goast.CallExpr { for i := range args { PanicIfNil(args[i], "Argument of function is cannot be nil") } fun := typeToExpr(functionName) if strings.HasPrefix(functionName, "*") { fun = &goast.ParenExpr{ X: fun, } } return &goast.CallExpr{ Fun: fun, Args: args, } } // NewFuncClosure creates a new *"go/ast".CallExpr that calls a function // literal closure. The first argument is the Go return type of the // closure, and the remainder of the arguments are the statements of the // closure body. func NewFuncClosure(returnType string, stmts ...goast.Stmt) *goast.CallExpr { return &goast.CallExpr{ Fun: &goast.FuncLit{ Type: NewFuncType(&goast.FieldList{}, returnType, false), Body: &goast.BlockStmt{ List: stmts, }, }, Args: []goast.Expr{}, } } // NewBinaryExpr create a new Go AST binary expression with a left, operator and // right operand. // // You should use this instead of BinaryExpr directly so that nil left and right // operands can be caught (and panic) before Go tried to render the source - // which would result in a very hard to debug error. // // Assignment operators in C can be nested inside other expressions, like: // // a + (b += 3) // // In Go this is not allowed. Since the operators mutate variables it is not // possible in some cases to move the statements before or after. The only safe // (and generic) way around this is to create an immediately executing closure, // like: // // a + (func () int { b += 3; return b }()) // // In a lot of cases this may be unnecessary and obfuscate the Go output but // these will have to be optimised over time and be strict about the // situation they are simplifying. // // If stmt is true then the binary expression is the whole statement. This means // that the closure above does not need to applied. This makes the output code // much neater. func NewBinaryExpr(left goast.Expr, operator token.Token, right goast.Expr, returnType string, stmt bool) goast.Expr { PanicIfNil(left, "left is nil") PanicIfNil(right, "right is nil") var b goast.Expr = &goast.BinaryExpr{ X: left, Op: operator, Y: right, } if !stmt && isAssignishOperator(operator) { return NewFuncClosure(returnType, NewExprStmt(b), &goast.ReturnStmt{ Results: []goast.Expr{left}, }) } return b } func isAssignishOperator(t token.Token) bool { switch t { case token.ADD_ASSIGN, // += token.SUB_ASSIGN, // -= token.MUL_ASSIGN, // *= token.QUO_ASSIGN, // /= token.REM_ASSIGN, // %= token.AND_ASSIGN, // &= token.OR_ASSIGN, // |= token.XOR_ASSIGN, // ^= token.SHL_ASSIGN, // <<= token.SHR_ASSIGN, // >>= token.AND_NOT_ASSIGN, // &^= token.ASSIGN: // = return true } return false } // NewIdent - create a new Go ast Ident func NewIdent(name string) *goast.Ident { // TODO: The name of a variable or field cannot be a reserved word // https://github.com/elliotchance/c2go/issues/83 // Search for this issue in other areas of the codebase. if IsGoKeyword(name) { name += "_" } // Remove const prefix as it has no equivalent in Go. name = strings.TrimPrefix(name, "const ") if !IsAValidFunctionName(name) { // Normally we do not panic because we want the transpiler to recover as // much as possible so that we always get Go output - even if it's // wrong. However, in this case we must panic because we know that this // identity will cause the AST renderer in Go to panic with a very // unhelpful error message. // // Panic now so that we can see where the bad identifier is coming from. panic(fmt.Sprintf("invalid identity: '%s'", name)) } return goast.NewIdent(name) } // NewTypeIdent created a new Go identity that is to be used for a Go type. This // is different from NewIdent in how the input string is validated. func NewTypeIdent(name string) goast.Expr { return typeToExpr(name) } // NewStringLit returns a new Go basic literal with a string value. func NewStringLit(value string) *goast.BasicLit { return &goast.BasicLit{ Kind: token.STRING, Value: value, } } // NewIntLit - create a Go ast BasicLit for `INT` value func NewIntLit(value int) *goast.BasicLit { return &goast.BasicLit{ Kind: token.INT, Value: strconv.Itoa(value), } } // NewFloatLit creates a new Float Literal. func NewFloatLit(value float64) *goast.BasicLit { return &goast.BasicLit{ Kind: token.FLOAT, Value: strconv.FormatFloat(value, 'g', -1, 64), } } // NewVaListTag creates a new VaList Literal. func NewVaListTag() goast.Expr { var p token.Pos elts := make([]goast.Expr, 2) elts[0] = &goast.KeyValueExpr{ Key: &goast.BasicLit{Kind: token.STRING, Value: "Pos"}, Colon: p, Value: &goast.BasicLit{Kind: token.STRING, Value: "0"}, } elts[1] = &goast.KeyValueExpr{ Key: &goast.BasicLit{Kind: token.STRING, Value: "Args"}, Colon: p, Value: &goast.BasicLit{Kind: token.STRING, Value: "c2goArgs"}, } return &goast.CompositeLit{ Type: &goast.BasicLit{Kind: token.STRING, Value: "noarch.VaList"}, Lbrace: p, Elts: elts, Rbrace: p, } } // NewNil returns a Go AST identity that can be used to represent "nil". func NewNil() *goast.Ident { return NewIdent("nil") } // NewUnaryExpr creates a new Go unary expression. You should use this function // instead of instantiating the UnaryExpr directly because this function has // extra error checking. func NewUnaryExpr(operator token.Token, right goast.Expr) *goast.UnaryExpr { if right == nil { panic("right is nil") } return &goast.UnaryExpr{ Op: operator, X: right, } } // IsGoKeyword will return true if a word is one of the reserved words in Go. // This means that it cannot be used as an identifier, function name, etc. // // The list of reserved words has been taken from the spec at // https://golang.org/ref/spec#Keywords func IsGoKeyword(w string) bool { switch w { case "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var", "_", "init": return true } return false } // ConvertFunctionNameFromCtoGo - convert function name fromC to Go func ConvertFunctionNameFromCtoGo(name string) string { if name == "_" { return "__" } return name } // CreatePointerFromReference - create a pointer, like : // (*int)(unsafe.Pointer(&a)) func CreatePointerFromReference(goType string, expr goast.Expr) (e goast.Expr) { // If the Go type is blank it means that the C type is 'void'. if goType == "" { goType = "unsafe.Pointer" } // You must always call this Go before using CreatePointerFromReference: // // p.AddImport("unsafe") // e = NewCallExpr("unsafe.Pointer", &goast.UnaryExpr{ X: expr, Op: token.AND, }) if goType != "unsafe.Pointer" { e = &goast.CallExpr{ Fun: &goast.ParenExpr{ X: NewTypeIdent(goType), }, Args: []goast.Expr{expr}, } } return } // CreateUnlimitedSliceFromReference - create a slice, like : // (*[1000000000]int)(unsafe.Pointer(&a))[:] func CreateUnlimitedSliceFromReference(goType string, expr goast.Expr) *goast.SliceExpr { // If the Go type is blank it means that the C type is 'void'. if goType == "" { goType = "interface{}" } // This is a hack to convert a reference to a variable into a slice that // points to the same location. It will look similar to: // // (*[1000000000]int)(unsafe.Pointer(&a))[:] // // You must always call this Go before using CreateUnlimitedSliceFromReference: // // p.AddImport("unsafe") // return &goast.SliceExpr{ X: NewCallExpr( fmt.Sprintf("(*[1000000000]%s)", goType), NewCallExpr("unsafe.Pointer", &goast.UnaryExpr{ X: expr, Op: token.AND, }), ), } } // NewFuncType - create a new function type, example: // func ...(fieldList)(returnType) func NewFuncType(fieldList *goast.FieldList, returnType string, addDefaultReturn bool) *goast.FuncType { returnTypes := []*goast.Field{} if returnType != "" { field := goast.Field{ Type: NewTypeIdent(returnType), } if addDefaultReturn { field.Names = []*goast.Ident{NewIdent("c2goDefaultReturn")} } returnTypes = append(returnTypes, &field) } return &goast.FuncType{ Params: fieldList, Results: &goast.FieldList{ List: returnTypes, }, } } // NewGoExpr is used to facilitate the creation of go AST // // It should not be used to transpile user code. func NewGoExpr(expr string) goast.Expr { e, err := parser.ParseExpr(expr) if err != nil { panic("programming error: " + expr) } return e } // NewAnonymousFunction - create a new anonymous function. // Example: // func() returnType{ // defer func(){ // deferBody // }() // body // return returnValue // } func NewAnonymousFunction(body, deferBody []goast.Stmt, returnValue goast.Expr, returnType string) *goast.CallExpr { if len(deferBody) > 0 { body = append(body, []goast.Stmt{&goast.DeferStmt{ Defer: 1, Call: &goast.CallExpr{ Fun: &goast.FuncLit{ Type: &goast.FuncType{}, Body: &goast.BlockStmt{List: deferBody}, }, Lparen: 1, }, }}...) } return &goast.CallExpr{Fun: &goast.FuncLit{ Type: &goast.FuncType{ Results: &goast.FieldList{List: []*goast.Field{ &goast.Field{Type: goast.NewIdent(returnType)}, }}, }, Body: &goast.BlockStmt{ List: append(body, &goast.ReturnStmt{ Results: []goast.Expr{returnValue}, }), }, }} } // IsAddressable returns whether it's possible to obtain an address of expr // using the unary & operator. func IsAddressable(expr goast.Expr) bool { if _, ok := expr.(*goast.Ident); ok { return true } if ie, ok := expr.(*goast.IndexExpr); ok { return IsAddressable(ie.X) } if pe, ok := expr.(*goast.ParenExpr); ok { return IsAddressable(pe.X) } return false } c2go-0.26.10/util/goast_test.go000066400000000000000000000012631410601753200161730ustar00rootroot00000000000000package util import ( "testing" ) var floats = []struct { in float64 out string }{ // Zeros have no decimal {0, "0"}, {-0, "0"}, {3.14159265, "3.14159265"}, // + sign is included in positive exponents {3.14159265e123, "3.14159265e+123"}, {3.14159265e+123, "3.14159265e+123"}, {3.14159265e-123, "3.14159265e-123"}, // "Small" exponents are not stored as exponents {3.14159265e+2, "314.159265"}, {3.14159265e+5, "314159.265"}, } func TestFloatLit(t *testing.T) { for _, tt := range floats { actual := NewFloatLit(tt.in).Value if tt.out != actual { t.Errorf("input: %v", tt.in) t.Errorf(" expected: %v", tt.out) t.Errorf(" actual: %v", actual) } } } c2go-0.26.10/util/regexp.go000066400000000000000000000022761410601753200153160ustar00rootroot00000000000000package util import ( "regexp" "strings" "sync" ) // GroupsFromRegex gets RegExp groups after matching it on a 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. rx = strings.Replace(rx, "\r", "", -1) rx = strings.Replace(rx, "\n", "", -1) rx = strings.Replace(rx, "\t", "", -1) re := GetRegex(rx) match := re.FindStringSubmatch(line) if len(match) == 0 { return nil } result := make(map[string]string) for i, name := range re.SubexpNames() { if i != 0 { result[name] = match[i] } } return result } // cachedRegex - structure for saving regexp`s type cachedRegex struct { sync.RWMutex m map[string]*regexp.Regexp } // Global variable var cr = cachedRegex{m: map[string]*regexp.Regexp{}} // GetRegex return regexp // added for minimaze regexp compilation func GetRegex(rx string) *regexp.Regexp { cr.RLock() v, ok := cr.m[rx] cr.RUnlock() if ok { return v } // if regexp is not in map cr.Lock() cr.m[rx] = regexp.MustCompile(rx) cr.Unlock() return GetRegex(rx) } c2go-0.26.10/util/test.go000066400000000000000000000016461410601753200150030ustar00rootroot00000000000000package util import ( "fmt" "math" "strconv" "strings" ) // ShowDiff will print two strings vertically next to each other so that line // differences are easier to read. func ShowDiff(a, b string) string { aLines := strings.Split(a, "\n") bLines := strings.Split(b, "\n") maxLines := int(math.Max(float64(len(aLines)), float64(len(bLines)))) out := "\n" for lineNumber := 0; lineNumber < maxLines; lineNumber++ { aLine := "" bLine := "" // Replace NULL characters with a dot. Otherwise the strings will look // exactly the same but have different length (and therfore not be // equal). if lineNumber < len(aLines) { aLine = strconv.Quote(aLines[lineNumber]) } if lineNumber < len(bLines) { bLine = strconv.Quote(bLines[lineNumber]) } diffFlag := " " if aLine != bLine { diffFlag = "*" } out += fmt.Sprintf("%s %3d %-40s%-40s\n", diffFlag, lineNumber+1, aLine, bLine) } return out } c2go-0.26.10/util/util.go000066400000000000000000000027061410601753200147770ustar00rootroot00000000000000package util import ( "strconv" "strings" ) // InStrings returns true if item exists in items. It must be an exact string // match. func InStrings(item string, items []string) bool { for _, v := range items { if item == v { return true } } return false } // Ucfirst returns the word with the first letter uppercased; none of the other // letters in the word are modified. For example "fooBar" would return "FooBar". func Ucfirst(word string) string { if word == "" { return "" } if len(word) == 1 { return strings.ToUpper(word) } return strings.ToUpper(string(word[0])) + word[1:] } // Atoi converts a string to an integer in cases where we are sure that s will // be a valid integer, otherwise it will panic. func Atoi(s string) int { i, err := strconv.Atoi(s) PanicOnError(err, "bad integer") return i } // GetExportedName returns a deterministic and Go safe name for a C type. For // example, "*__foo[]" will return "FooSlice". func GetExportedName(field string) string { if strings.Contains(field, "interface{}") || strings.Contains(field, "Interface{}") { return "Interface" } // Convert "[]byte" into "byteSlice". This also works with multiple slices, // like "[][]byte" to "byteSliceSlice". for len(field) > 2 && field[:2] == "[]" { field = field[2:] + "Slice" } // NotFunc(int)() field = strings.Replace(field, "(", "_", -1) field = strings.Replace(field, ")", "_", -1) return Ucfirst(strings.TrimLeft(field, "*_")) }