github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/program/program.go (about)

     1  // Package program contains high-level orchestration and state of the input and
     2  // output program during transpilation.
     3  package program
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"go/format"
     9  	"go/token"
    10  	"os"
    11  
    12  	goast "go/ast"
    13  
    14  	"strings"
    15  
    16  	"github.com/Konstantin8105/c4go/ast"
    17  	"github.com/Konstantin8105/c4go/preprocessor"
    18  	"github.com/Konstantin8105/c4go/util"
    19  )
    20  
    21  // StructRegistry is a map of Struct for struct types and union type
    22  type StructRegistry map[string]*Struct
    23  
    24  // HasType method check if type exists
    25  func (sr StructRegistry) HasType(typename string) bool {
    26  	_, exists := sr[typename]
    27  
    28  	return exists
    29  }
    30  
    31  // Program contains all of the input, output and transpition state of a C
    32  // program to a Go program.
    33  type Program struct {
    34  	// All of the Go import paths required for this program.
    35  	imports []string
    36  
    37  	// These are for the output Go AST.
    38  	FileSet *token.FileSet
    39  	File    *goast.File
    40  
    41  	// One a type is defined it will be ignored if a future type of the same
    42  	// name appears.
    43  	typesAlreadyDefined []string
    44  
    45  	// Contains the current function name during the transpilation.
    46  	Function *ast.FunctionDecl
    47  
    48  	functionDefinitions                      map[string]DefinitionFunction
    49  	builtInFunctionDefinitionsHaveBeenLoaded bool
    50  
    51  	// These are used to setup the runtime before the application begins. An
    52  	// example would be to setup globals with stdin file pointers on certain
    53  	// platforms.
    54  	startupStatements []goast.Stmt
    55  
    56  	// This is used to generate globally unique names for temporary variables
    57  	// and other generated code. See GetNextIdentifier().
    58  	nextUniqueIdentifier int
    59  
    60  	// The definitions for defined structs.
    61  	// TODO: This field should be protected through proper getters and setters.
    62  	Structs StructRegistry
    63  	Unions  StructRegistry
    64  
    65  	// If verbose is on progress messages will be printed immediately as code
    66  	// comments (so that they do not interfere with the program output).
    67  	Verbose bool
    68  
    69  	// Contains the messages (for example, "// Warning") generated when
    70  	// transpiling the AST. These messages, which are code comments, are
    71  	// appended to the very top of the output file. See AddMessage().
    72  	messages []string
    73  
    74  	// messagePosition - position of slice messages, added like a comment
    75  	// in output Go code
    76  	messagePosition int
    77  
    78  	// A map of all the global variables (variables that exist outside of a
    79  	// function) and their types.
    80  	GlobalVariables map[string]string
    81  
    82  	// EnumConstantToEnum - a map with key="EnumConstant" and value="enum type"
    83  	// clang don`t show enum constant with enum type,
    84  	// so we have to use hack for repair the type
    85  	EnumConstantToEnum map[string]string
    86  
    87  	// EnumTypedefName - a map with key="Name of typedef enum" and
    88  	// value="exist ot not"
    89  	EnumTypedefName map[string]bool
    90  
    91  	// TypedefType - map for type alias, for example:
    92  	// C  : typedef int INT;
    93  	// Map: key = INT, value = int
    94  	// Important: key and value are C types
    95  	TypedefType map[string]string
    96  
    97  	// commentLine - a map with:
    98  	// key    - filename
    99  	// value  - last comment inserted in Go code
   100  	commentLine map[string]commentPos
   101  
   102  	// preprocessor file
   103  	PreprocessorFile preprocessor.FilePP
   104  
   105  	// UnsafeConvertValueToPointer - simplification for convert value to pointer
   106  	UnsafeConvertValueToPointer map[string]bool
   107  
   108  	// UnsafeConvertPointerArith - simplification for pointer arithmetic
   109  	UnsafeConvertPointerArith map[string]bool
   110  
   111  	// IsHaveVaList
   112  	IsHaveVaList bool
   113  
   114  	DoNotAddComments bool
   115  
   116  	// for binding parse FunctionDecl one time
   117  	Binding bool
   118  }
   119  
   120  type commentPos struct {
   121  	pos  int // index in comments slice
   122  	line int // line position
   123  }
   124  
   125  // NewProgram creates a new blank program.
   126  func NewProgram() (p *Program) {
   127  	defer func() {
   128  		// Need for "stdbool.h"
   129  		p.TypedefType["_Bool"] = "int"
   130  		// Initialization c4go implementation of CSTD structs
   131  		p.initializationStructs()
   132  	}()
   133  	return &Program{
   134  		imports:             []string{},
   135  		typesAlreadyDefined: []string{},
   136  		startupStatements:   []goast.Stmt{},
   137  		Structs:             StructRegistry(map[string]*Struct{
   138  			// Structs without implementations inside system C headers
   139  			// Example node for adding:
   140  			// &ast.TypedefDecl{ ... Type:"struct __locale_struct *" ... }
   141  		}),
   142  		Unions:                                   make(StructRegistry),
   143  		Verbose:                                  false,
   144  		messages:                                 []string{},
   145  		GlobalVariables:                          map[string]string{},
   146  		EnumConstantToEnum:                       map[string]string{},
   147  		EnumTypedefName:                          map[string]bool{},
   148  		TypedefType:                              map[string]string{},
   149  		commentLine:                              map[string]commentPos{},
   150  		functionDefinitions:                      map[string]DefinitionFunction{},
   151  		builtInFunctionDefinitionsHaveBeenLoaded: false,
   152  		UnsafeConvertValueToPointer:              map[string]bool{},
   153  		UnsafeConvertPointerArith:                map[string]bool{},
   154  	}
   155  }
   156  
   157  // AddMessage adds a message (such as a warning or error) comment to the output
   158  // file. Usually the message is generated from one of the Generate functions in
   159  // the ast package.
   160  //
   161  // It is expected that the message already have the comment ("//") prefix.
   162  //
   163  // The message will not be appended if it is blank. This is because the Generate
   164  // functions return a blank string conditionally when there is no error.
   165  //
   166  // The return value will be true if a message was added, otherwise false.
   167  func (p *Program) AddMessage(message string) bool {
   168  	if message == "" {
   169  		return false
   170  	}
   171  
   172  	p.messages = append(p.messages, message)
   173  
   174  	// Compactizarion warnings stack
   175  	if len(p.messages) > 1 {
   176  		var (
   177  			new  = len(p.messages) - 1
   178  			last = len(p.messages) - 2
   179  		)
   180  		// Warning collapsing for minimize warnings
   181  		warning := "// Warning"
   182  		if strings.HasPrefix(p.messages[last], warning) {
   183  			l := p.messages[last][len(warning):]
   184  			if strings.HasSuffix(p.messages[new], l) {
   185  				p.messages[last] = p.messages[new]
   186  				p.messages = p.messages[0:new]
   187  			}
   188  		}
   189  	}
   190  
   191  	return true
   192  }
   193  
   194  // GetMessageComments - get messages "Warnings", "Error" like a comment
   195  // Location of comments only NEAR of error or warning and
   196  // don't show directly location
   197  func (p *Program) GetMessageComments() (_ *goast.CommentGroup) {
   198  	var group goast.CommentGroup
   199  	if p.messagePosition < len(p.messages) {
   200  		for i := p.messagePosition; i < len(p.messages); i++ {
   201  			group.List = append(group.List, &goast.Comment{
   202  				Text: p.messages[i],
   203  			})
   204  		}
   205  		p.messagePosition = len(p.messages)
   206  	}
   207  	return &group
   208  }
   209  
   210  // GetComments - return comments
   211  func (p *Program) GetComments(n ast.Position) (out []*goast.Comment) {
   212  	if p.DoNotAddComments {
   213  		return
   214  	}
   215  	beginLine := p.commentLine[n.File]
   216  	if n.Line < beginLine.line {
   217  		return
   218  	}
   219  	comms := p.PreprocessorFile.GetComments()
   220  	for i := beginLine.pos; i < len(comms); i++ {
   221  		if comms[i].File != n.File {
   222  			continue
   223  		}
   224  		if comms[i].Line <= beginLine.line {
   225  			continue
   226  		}
   227  		if comms[i].Line > n.Line {
   228  			break
   229  		}
   230  		// add comment
   231  		out = append(out, &goast.Comment{
   232  			Text: comms[i].Comment,
   233  		})
   234  		beginLine.pos = i
   235  		if comms[i].Comment[1] == '*' {
   236  			out = append(out, &goast.Comment{
   237  				Text: "// ",
   238  			})
   239  		}
   240  	}
   241  	beginLine.line = n.Line
   242  	p.commentLine[n.File] = beginLine
   243  	return
   244  }
   245  
   246  // GetStruct returns a struct object (representing struct type or union type) or
   247  // nil if doesn't exist. This method can get struct or union in the same way and
   248  // distinguish only by the IsUnion field. `name` argument is the C like
   249  // `struct a_struct`, it allow pointer type like `union a_union *`. Pointer
   250  // types used in a DeclRefExpr in the case a deferenced structure by using `->`
   251  // operator to access to a field like this: a_struct->member .
   252  //
   253  // This method is used in collaboration with the field
   254  // "c4go/program".*Struct.IsUnion to simplify the code like in function
   255  // "c4go/transpiler".transpileMemberExpr() where the same *Struct value returned
   256  // by this method is used in the 2 cases, in the case where the value has a
   257  // struct type and in the case where the value has an union type.
   258  func (p *Program) GetStruct(name string) *Struct {
   259  	if name == "" {
   260  		return nil
   261  	}
   262  
   263  	// That allow to get struct from pointer type
   264  	if last := len(name) - 1; name[last] == '*' {
   265  		name = name[:last]
   266  	}
   267  
   268  	name = strings.TrimSpace(name)
   269  
   270  	res, ok := p.Structs[name]
   271  	if ok {
   272  		return res
   273  	}
   274  	res, ok = p.Unions[name]
   275  	if ok {
   276  		return res
   277  	}
   278  
   279  	return nil
   280  }
   281  
   282  // IsTypeAlreadyDefined will return true if the typeName has already been
   283  // defined.
   284  //
   285  // A type could be defined:
   286  //
   287  // 1. Initially. That is, before the transpilation starts (hard-coded).
   288  // 2. By calling DefineType throughout the transpilation.
   289  func (p *Program) IsTypeAlreadyDefined(typeName string) bool {
   290  	return util.InStrings(typeName, p.typesAlreadyDefined)
   291  }
   292  
   293  // DefineType will record a type as having already been defined. The purpose for
   294  // this is to not generate Go for a type more than once. C allows variables and
   295  // other entities (such as function prototypes) to be defined more than once in
   296  // some cases. An example of this would be static variables or functions.
   297  func (p *Program) DefineType(typeName string) {
   298  	p.typesAlreadyDefined = append(p.typesAlreadyDefined, typeName)
   299  }
   300  
   301  // UndefineType undefine defined type
   302  func (p *Program) UndefineType(typeName string) {
   303  check_again:
   304  	for i := range p.typesAlreadyDefined {
   305  		if typeName == p.typesAlreadyDefined[i] {
   306  			if len(p.typesAlreadyDefined) == 1 {
   307  				p.typesAlreadyDefined = make([]string, 0)
   308  			} else if i == len(p.typesAlreadyDefined)-1 {
   309  				p.typesAlreadyDefined = p.typesAlreadyDefined[:len(p.typesAlreadyDefined)-1]
   310  			} else {
   311  				p.typesAlreadyDefined = append(
   312  					p.typesAlreadyDefined[:i],
   313  					p.typesAlreadyDefined[i+1:]...)
   314  			}
   315  			goto check_again
   316  		}
   317  	}
   318  }
   319  
   320  // GetNextIdentifier generates a new globally unique identifier name. This can
   321  // be used for variables and functions in generated code.
   322  //
   323  // The value of prefix is only useful for readability in the code. If the prefix
   324  // is an empty string then the prefix "__temp" will be used.
   325  func (p *Program) GetNextIdentifier(prefix string) string {
   326  	if prefix == "" {
   327  		prefix = "temp"
   328  	}
   329  
   330  	identifierName := fmt.Sprintf("%s%d", prefix, p.nextUniqueIdentifier)
   331  	p.nextUniqueIdentifier++
   332  
   333  	return identifierName
   334  }
   335  
   336  type nilWalker struct {
   337  }
   338  
   339  func (n nilWalker) Visit(node goast.Node) (w goast.Visitor) {
   340  	fmt.Fprintf(os.Stdout, "\n---------\n")
   341  	fmt.Fprintf(os.Stdout, "Node: %#v\n", node)
   342  	switch v := node.(type) {
   343  	case *goast.IndexExpr:
   344  		fmt.Fprintf(os.Stdout, "IndexExpr\n")
   345  		fmt.Fprintf(os.Stdout, "\tx     = %#v\n", v.X)
   346  		fmt.Fprintf(os.Stdout, "\tindex = %#v\n", v.Index)
   347  		if v.Index == nil {
   348  			goast.Print(token.NewFileSet(), v)
   349  			panic("")
   350  		}
   351  
   352  	case *goast.GenDecl:
   353  		fmt.Fprintf(os.Stdout, "%#v\n", v)
   354  		for i, s := range v.Specs {
   355  			fmt.Fprintf(os.Stdout, "Spec%d:   %#v\n", i, s)
   356  			if vs, ok := s.(*goast.ValueSpec); ok {
   357  				for j := range vs.Names {
   358  					fmt.Fprintf(os.Stdout, "IDS : %#v\n", vs.Names[j])
   359  				}
   360  			}
   361  		}
   362  	}
   363  	return n
   364  }
   365  
   366  type simpleDefer struct {
   367  }
   368  
   369  func (s simpleDefer) Visit(node goast.Node) (w goast.Visitor) {
   370  	// 	var s int32 = func() int32 {
   371  	// 		if int32(sstr_s[0]) == int32(sstr_bufs[sstr_n]) {
   372  	// 			return 1
   373  	// 		}
   374  	// 		return 0
   375  	// 	}()
   376  
   377  	// from :
   378  	//		{
   379  	//			...
   380  	//			li = func() int32 {
   381  	//				if booled {
   382  	//					return result1
   383  	//				}
   384  	//				return result2
   385  	//			}()
   386  	//			...
   387  	//		}
   388  	// to   :
   389  	//		{
   390  	//			...
   391  	//			if booled {
   392  	//				li = result1
   393  	//			} else {
   394  	//				li = result2
   395  	//			}
   396  	//			...
   397  	//		}
   398  	if eb, ok := node.(*goast.BlockStmt); ok && 0 < len(eb.List) {
   399  		for i := range eb.List {
   400  			if eb.List[i] == nil {
   401  				continue
   402  			}
   403  			es, ok := eb.List[i].(*goast.ExprStmt)
   404  			if !ok {
   405  				continue
   406  			}
   407  			be, ok := es.X.(*goast.BinaryExpr)
   408  			if !ok {
   409  				continue
   410  			}
   411  
   412  			valueName := be.X
   413  			if be.Op != token.ASSIGN {
   414  				continue
   415  			}
   416  			cl, ok := be.Y.(*goast.CallExpr)
   417  			if !ok {
   418  				continue
   419  			}
   420  			fl, ok := cl.Fun.(*goast.FuncLit)
   421  			if !ok {
   422  				continue
   423  			}
   424  			b := fl.Body
   425  			if 2 != len(b.List) {
   426  				continue
   427  			}
   428  			ifd, ok := b.List[0].(*goast.IfStmt)
   429  			if !ok {
   430  				continue
   431  			}
   432  
   433  			condition := ifd.Cond
   434  
   435  			ifbod := ifd.Body
   436  			if 1 != len(ifbod.List) {
   437  				continue
   438  			}
   439  
   440  			ret1, ok := ifbod.List[0].(*goast.ReturnStmt)
   441  			if !ok {
   442  				continue
   443  			}
   444  
   445  			result1 := ret1.Results
   446  
   447  			ret2, ok := b.List[1].(*goast.ReturnStmt)
   448  			if !ok {
   449  				continue
   450  			}
   451  
   452  			result2 := ret2.Results
   453  
   454  			eb.List[i] = &goast.IfStmt{
   455  				Cond: condition,
   456  				Body: &goast.BlockStmt{
   457  					List: []goast.Stmt{
   458  						&goast.AssignStmt{
   459  							Lhs: []goast.Expr{valueName},
   460  							Tok: token.ASSIGN,
   461  							Rhs: result1,
   462  						},
   463  					},
   464  				},
   465  				Else: &goast.BlockStmt{
   466  					List: []goast.Stmt{
   467  						&goast.AssignStmt{
   468  							Lhs: []goast.Expr{valueName},
   469  							Tok: token.ASSIGN,
   470  							Rhs: result2,
   471  						},
   472  					},
   473  				},
   474  			}
   475  		}
   476  	}
   477  
   478  	// from :
   479  	//		if ... {
   480  	//			{
   481  	//				...
   482  	//			}
   483  	//		} else {
   484  	//			{
   485  	//				...
   486  	//			}
   487  	//		}
   488  	// to   :
   489  	//		if ... {
   490  	//				...
   491  	//		} else {
   492  	//				...
   493  	//		}
   494  	if fb, ok := node.(*goast.IfStmt); ok {
   495  		if len(fb.Body.List) == 1 {
   496  			if ib, ok := fb.Body.List[0].(*goast.BlockStmt); ok {
   497  				fb.Body = ib
   498  			}
   499  		}
   500  		if fb.Else != nil {
   501  			if b1, ok := fb.Else.(*goast.BlockStmt); ok && 1 == len(b1.List) {
   502  				if b2, ok := b1.List[0].(*goast.BlockStmt); ok {
   503  					fb.Else = b2
   504  				}
   505  			}
   506  		}
   507  	}
   508  
   509  	// from :
   510  	//		return func() int32 {
   511  	//			if int32(sstr_s[0]) == int32(sstr_bufs[sstr_n]) {
   512  	//				return 1
   513  	//			}
   514  	//			return 0
   515  	//		}()
   516  	// or   :
   517  	//		return func() int32 {
   518  	//			...
   519  	//		}()
   520  	// to   :
   521  	//		if int32(sstr_s[0]) == int32(sstr_bufs[sstr_n]) {
   522  	//			return 1
   523  	//		}
   524  	//		return 0
   525  	// or   :
   526  	//		...
   527  	if eb, ok := node.(*goast.BlockStmt); ok && 0 < len(eb.List) {
   528  		if ret, ok := eb.List[len(eb.List)-1].(*goast.ReturnStmt); ok && 1 == len(ret.Results) {
   529  			if c, ok := ret.Results[0].(*goast.CallExpr); ok {
   530  				if fl, ok := c.Fun.(*goast.FuncLit); ok {
   531  					if 1 < len(eb.List) {
   532  						eb.List = eb.List[:len(eb.List)-1]
   533  					} else {
   534  						eb.List = []goast.Stmt{}
   535  					}
   536  					eb.List = append(eb.List, fl.Body.List...)
   537  				}
   538  			}
   539  		}
   540  	}
   541  
   542  	// from :
   543  	//		{
   544  	//			.....
   545  	//			func() []byte {
   546  	//				tempVarUnary := sstr_s
   547  	//				defer func() {
   548  	//					sstr_s = f(sstr_s, int(-1))
   549  	//				}()
   550  	//				return tempVarUnary
   551  	//			}()
   552  	//			.....
   553  	//		}
   554  	// to   :
   555  	//		{
   556  	//			.....
   557  	//			sstr_s = f(sstr_s, int(-1))
   558  	//			.....
   559  	//		}
   560  	if eb, ok := node.(*goast.BlockStmt); ok {
   561  		for i := range eb.List {
   562  			es, ok := eb.List[i].(*goast.ExprStmt)
   563  			if !ok {
   564  				continue
   565  			}
   566  			cl, ok := es.X.(*goast.CallExpr)
   567  			if !ok {
   568  				continue
   569  			}
   570  			fl, ok := cl.Fun.(*goast.FuncLit)
   571  			if !ok {
   572  				continue
   573  			}
   574  			ft := fl.Type // .(*goast.FuncType)
   575  			if 1 != len(ft.Results.List) {
   576  				continue
   577  			}
   578  
   579  			if 3 != len(fl.Body.List) {
   580  				continue
   581  			}
   582  
   583  			body := fl.Body.List
   584  
   585  			as, ok := body[0].(*goast.AssignStmt)
   586  			if !ok {
   587  				continue
   588  			}
   589  			if 1 != len(as.Lhs) {
   590  				continue
   591  			}
   592  			in, ok := as.Lhs[0].(*goast.Ident)
   593  			if !ok {
   594  				continue
   595  			}
   596  			if in.Name != "tempVarUnary" {
   597  				continue
   598  			}
   599  
   600  			rt, ok := body[2].(*goast.ReturnStmt)
   601  			if !ok {
   602  				continue
   603  			}
   604  			if 1 != len(rt.Results) {
   605  				continue
   606  			}
   607  			id, ok := rt.Results[0].(*goast.Ident)
   608  			if !ok {
   609  				continue
   610  			}
   611  			if id.Name != "tempVarUnary" {
   612  				continue
   613  			}
   614  
   615  			def, ok := body[1].(*goast.DeferStmt)
   616  			if !ok {
   617  				continue
   618  			}
   619  
   620  			fl, ok = def.Call.Fun.(*goast.FuncLit)
   621  			if !ok {
   622  				continue
   623  			}
   624  
   625  			body = fl.Body.List
   626  			if 1 != len(body) {
   627  				continue
   628  			}
   629  
   630  			eb.List[i] = body[0]
   631  		}
   632  	}
   633  
   634  	// 	from:
   635  	//		func f4() {
   636  	//			{
   637  	//				var i int32
   638  	//				for ; i < 10; i++ {
   639  	//				}
   640  	//			}
   641  	//		}
   642  	// to   :
   643  	//		func f4() {
   644  	//			var i int32
   645  	//			for ; i < 10; i++ {
   646  	//			}
   647  	//		}
   648  	if fd, ok := node.(*goast.FuncDecl); ok && len(fd.Body.List) == 1 {
   649  		if ib, ok := fd.Body.List[0].(*goast.BlockStmt); ok {
   650  			fd.Body = ib // internal body
   651  		}
   652  	}
   653  	// 	from:
   654  	//		 {
   655  	//			{
   656  	//				var i int32
   657  	//				for ; i < 10; i++ {
   658  	//				}
   659  	//			}
   660  	//		}
   661  	// to   :
   662  	//		{
   663  	//			var i int32
   664  	//			for ; i < 10; i++ {
   665  	//			}
   666  	//		}
   667  	if eb, ok := node.(*goast.BlockStmt); ok && len(eb.List) == 1 {
   668  		if ib, ok := eb.List[0].(*goast.BlockStmt); ok {
   669  			eb = ib // internal body
   670  		}
   671  	}
   672  	// Simplification from :
   673  	//	var cc int32 = int32(uint8((func() []byte {
   674  	//		defer func() {
   675  	//			func() []byte {
   676  	//				tempVarUnary := ss
   677  	//				defer func() {
   678  	//					ss = ss[0+1:]
   679  	//				}()
   680  	//				return tempVarUnary
   681  	//			}()
   682  	//		}()
   683  	//		return ss
   684  	//	}())[0]))
   685  	//
   686  	// to:
   687  	//	var cc int32 = int32(uint8((func() []byte {
   688  	//		defer func() {
   689  	//			ss = ss[0+1:]
   690  	//		}()
   691  	//		return ss
   692  	//	}())[0]))
   693  	if f0, ok := node.(*goast.FuncLit); ok && f0.Body != nil {
   694  		if len(f0.Body.List) == 2 {
   695  			if df, ok := f0.Body.List[0].(*goast.DeferStmt); ok {
   696  				cl := df.Call
   697  				if fl, ok := cl.Fun.(*goast.FuncLit); ok && len(fl.Body.List) == 1 {
   698  					if es, ok := fl.Body.List[0].(*goast.ExprStmt); ok {
   699  						if cl, ok := es.X.(*goast.CallExpr); ok {
   700  							if fl, ok := cl.Fun.(*goast.FuncLit); ok && len(fl.Body.List) == 3 {
   701  								if _, ok := fl.Body.List[0].(*goast.AssignStmt); ok {
   702  									if df, ok := fl.Body.List[1].(*goast.DeferStmt); ok {
   703  										if _, ok := fl.Body.List[2].(*goast.ReturnStmt); ok {
   704  											f0.Body.List[0] = df
   705  										}
   706  									}
   707  								}
   708  							}
   709  						}
   710  					}
   711  				}
   712  			}
   713  		}
   714  	}
   715  
   716  	return s
   717  }
   718  
   719  // String generates the whole output Go file as a string. This will include the
   720  // messages at the top of the file and all the rendered Go code.
   721  func (p *Program) String() string {
   722  	var buf bytes.Buffer
   723  
   724  	buf.WriteString(fmt.Sprintf(`//
   725  //	Package - transpiled by c4go
   726  //
   727  //	If you have found any issues, please raise an issue at:
   728  //	https://github.com/Konstantin8105/c4go/
   729  //
   730  
   731  `))
   732  
   733  	// Simplification from :
   734  	//	var cc int32 = int32(uint8((func() []byte {
   735  	//		defer func() {
   736  	//			func() []byte {
   737  	//				tempVarUnary := ss
   738  	//				defer func() {
   739  	//					ss = ss[0+1:]
   740  	//				}()
   741  	//				return tempVarUnary
   742  	//			}()
   743  	//		}()
   744  	//		return ss
   745  	//	}())[0]))
   746  	//
   747  	// to:
   748  	//	var cc int32 = int32(uint8((func() []byte {
   749  	//		defer func() {
   750  	//			ss = ss[0+1:]
   751  	//		}()
   752  	//		return ss
   753  	//	}())[0]))
   754  	goast.Walk(new(simpleDefer), p.File)
   755  
   756  	// Only for debugging
   757  	// goast.Walk(new(nilWalker), p.File)
   758  
   759  	// First write all the messages. The double newline afterwards is important
   760  	// so that the package statement has a newline above it so that the warnings
   761  	// are not part of the documentation for the package.
   762  	buf.WriteString(strings.Join(p.messages, "\n") + "\n\n")
   763  
   764  	if err := format.Node(&buf, p.FileSet, p.File); err != nil {
   765  		// Printing the entire AST will generate a lot of output. However, it is
   766  		// the only way to debug this type of error. Hopefully the error
   767  		// (printed immediately afterwards) will give a clue.
   768  		//
   769  		// You may see an error like:
   770  		//
   771  		//     panic: format.Node internal error (692:23: expected selector or
   772  		//     type assertion, found '[')
   773  		//
   774  		// This means that when Go was trying to convert the Go AST to source
   775  		// code it has come across a value or attribute that is illegal.
   776  		//
   777  		// The line number it is referring to (in this case, 692) is not helpful
   778  		// as it references the internal line number of the Go code which you
   779  		// will never see.
   780  		//
   781  		// The "[" means that there is a bracket in the wrong place. Almost
   782  		// certainly in an identifer, like:
   783  		//
   784  		//     noarch.IntTo[]byte("foo")
   785  		//
   786  		// The "[]" which is obviously not supposed to be in the function name
   787  		// is causing the syntax error. However, finding the original code that
   788  		// produced this can be tricky.
   789  		//
   790  		// The first step is to filter down the AST output to probably lines.
   791  		// In the error message it said that there was a misplaced "[" so that's
   792  		// what we will search for. Using the original command (that generated
   793  		// thousands of lines) we will add two grep filters:
   794  		//
   795  		//     go test ... | grep "\[" | grep -v '{$'
   796  		//     #                   |     |
   797  		//     #                   |     ^ This excludes lines that end with "{"
   798  		//     #                   |       which almost certainly won't be what
   799  		//     #                   |       we are looking for.
   800  		//     #                   |
   801  		//     #                   ^ This is the character we are looking for.
   802  		//
   803  		// Hopefully in the output you should see some lines, like (some lines
   804  		// removed for brevity):
   805  		//
   806  		//     9083  .  .  .  .  .  .  .  .  .  .  Name: "noarch.[]byteTo[]int"
   807  		//     9190  .  .  .  .  .  .  .  .  .  Name: "noarch.[]intTo[]byte"
   808  		//
   809  		// These two lines are clearly the error because a name should not look
   810  		// like this.
   811  		//
   812  		// Looking at the full output of the AST (thousands of lines) and
   813  		// looking at those line numbers should give you a good idea where the
   814  		// error is coming from; by looking at the parents of the bad lines.
   815  		_ = goast.Print(p.FileSet, p.File)
   816  
   817  		panic(err)
   818  	}
   819  
   820  	// Add comments at the end C file
   821  	for file, beginLine := range p.commentLine {
   822  		for i := range p.PreprocessorFile.GetComments() {
   823  			if p.PreprocessorFile.GetComments()[i].File == file {
   824  				if beginLine.line < p.PreprocessorFile.GetComments()[i].Line {
   825  					buf.WriteString(
   826  						fmt.Sprintln(
   827  							p.PreprocessorFile.GetComments()[i].Comment))
   828  				}
   829  			}
   830  		}
   831  	}
   832  
   833  	// simplify Go code. Example :
   834  	// Before:
   835  	// func compare(a interface {
   836  	// }, b interface {
   837  	// }) (c4goDefaultReturn int) {
   838  	// After :
   839  	// func compare(a interface {}, b interface {}) (c4goDefaultReturn int) {
   840  	reg := util.GetRegex("interface( )?{(\r*)\n(\t*)}")
   841  	s := string(reg.ReplaceAll(buf.Bytes(), []byte("interface {}")))
   842  
   843  	sp := strings.Split(s, "\n")
   844  	for i := range sp {
   845  		if strings.HasSuffix(sp[i], "-= 1") {
   846  			sp[i] = strings.TrimSuffix(sp[i], "-= 1") + "--"
   847  		}
   848  		if strings.HasSuffix(sp[i], "+= 1") {
   849  			sp[i] = strings.TrimSuffix(sp[i], "+= 1") + "++"
   850  		}
   851  	}
   852  
   853  	return strings.Join(sp, "\n")
   854  }
   855  
   856  // IncludeHeaderIsExists return true if C #include header is inside list
   857  func (p *Program) IncludeHeaderIsExists(includeHeader string) bool {
   858  	for _, inc := range p.PreprocessorFile.GetIncludeFiles() {
   859  		if strings.HasSuffix(inc.HeaderName, includeHeader) {
   860  			return true
   861  		}
   862  	}
   863  	return false
   864  }