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

     1  // This file contains transpiling functions for literals and constants. Literals
     2  // are single values like 123 or "hello".
     3  
     4  package transpiler
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"go/token"
    10  	"regexp"
    11  	"strings"
    12  
    13  	goast "go/ast"
    14  
    15  	"strconv"
    16  
    17  	"github.com/Konstantin8105/c4go/ast"
    18  	"github.com/Konstantin8105/c4go/program"
    19  	"github.com/Konstantin8105/c4go/types"
    20  	"github.com/Konstantin8105/c4go/util"
    21  )
    22  
    23  func transpileFloatingLiteral(n *ast.FloatingLiteral) *goast.BasicLit {
    24  	return util.NewFloatLit(n.Value)
    25  }
    26  
    27  var regexpUnsigned *regexp.Regexp
    28  var regexpLongDouble *regexp.Regexp
    29  
    30  func init() {
    31  	regexpUnsigned = regexp.MustCompile(`%(\d+)?u`)
    32  	regexpLongDouble = regexp.MustCompile(`%(\d+)?(.\d+)?lf`)
    33  }
    34  
    35  // ConvertToGoFlagFormat convert format flags from C to Go
    36  func ConvertToGoFlagFormat(str string) string {
    37  	// %u to %d
    38  	{
    39  		match := regexpUnsigned.FindAllStringSubmatch(str, -1)
    40  		for _, sub := range match {
    41  			str = strings.Replace(str, sub[0], sub[0][:len(sub[0])-1]+"d", -1)
    42  		}
    43  	}
    44  	// from %lf to %f
    45  	{
    46  		match := regexpLongDouble.FindAllStringSubmatch(str, -1)
    47  		for _, sub := range match {
    48  			str = strings.Replace(str, sub[0], sub[0][:len(sub[0])-2]+"f", -1)
    49  		}
    50  	}
    51  	return str
    52  }
    53  
    54  func transpileStringLiteral(p *program.Program, n *ast.StringLiteral, arrayToArray bool) (
    55  	expr goast.Expr, exprType string, err error) {
    56  
    57  	// Convert format flags
    58  	n.Value = ConvertToGoFlagFormat(n.Value)
    59  
    60  	// Example:
    61  	// StringLiteral 0x280b918 <col:29> 'char [30]' lvalue "%0"
    62  	baseType := types.GetBaseType(n.Type)
    63  	if baseType != "char" &&
    64  		!strings.Contains(baseType, "int") &&
    65  		!strings.Contains(baseType, "wchar_t") {
    66  		if t, ok := p.TypedefType[baseType]; ok {
    67  			n.Type = t
    68  		} else {
    69  			err = fmt.Errorf("type is not valid : `%v`", n.Type)
    70  			p.AddMessage(p.GenerateWarningMessage(err, n))
    71  			return
    72  		}
    73  	}
    74  	var s int
    75  	s, err = types.GetAmountArraySize(n.Type, p)
    76  	if !arrayToArray {
    77  		if err != nil {
    78  			expr = util.NewCallExpr("[]byte",
    79  				util.NewStringLit(strconv.Quote(n.Value+"\x00")))
    80  			exprType = "const char *"
    81  			err = nil // ignore error
    82  			return
    83  		}
    84  		buf := bytes.NewBufferString(n.Value + "\x00")
    85  		if buf.Len() < s {
    86  			buf.Write(make([]byte, s-buf.Len()))
    87  		}
    88  		switch {
    89  		case strings.Contains(baseType, "int"), strings.Contains(baseType, "wchar_t"):
    90  			expr = util.NewCallExpr("[]rune",
    91  				util.NewStringLit(strconv.Quote(buf.String())))
    92  			exprType = "const wchar_t *"
    93  		default:
    94  			expr = util.NewCallExpr("[]byte",
    95  				util.NewStringLit(strconv.Quote(buf.String())))
    96  			exprType = "const char *"
    97  		}
    98  		return
    99  	}
   100  	// Example:
   101  	//
   102  	// var sba SBA = SBA{10, func() (b [100]byte) {
   103  	// 	copy(b[:], "qwe")
   104  	// 	return b
   105  	// }()}
   106  	expr = goast.NewIdent(fmt.Sprintf(
   107  		"func() (b [%v]byte) {copy(b[:], %s);return }()",
   108  		s, strconv.Quote(n.Value)))
   109  	exprType = n.Type
   110  	return
   111  }
   112  
   113  func transpileIntegerLiteral(n *ast.IntegerLiteral) *goast.BasicLit {
   114  	return &goast.BasicLit{
   115  		Kind:  token.INT,
   116  		Value: n.Value,
   117  	}
   118  }
   119  
   120  func transpileCharacterLiteral(n *ast.CharacterLiteral) *goast.BasicLit {
   121  	return &goast.BasicLit{
   122  		Kind:  token.CHAR,
   123  		Value: fmt.Sprintf("%q", n.Value),
   124  	}
   125  }
   126  
   127  func transpilePredefinedExpr(n *ast.PredefinedExpr, p *program.Program) (
   128  	expr goast.Expr, exprType string, err error) {
   129  
   130  	if len(n.Children()) == 1 {
   131  		expr, exprType, _, _, err = transpileToExpr(n.Children()[0], p, false)
   132  		return
   133  	}
   134  
   135  	// There are many more.
   136  	err = fmt.Errorf("unknown PredefinedExpr: %s", n.Name)
   137  	return
   138  }
   139  
   140  func transpileCompoundLiteralExpr(n *ast.CompoundLiteralExpr, p *program.Program) (goast.Expr, string, error) {
   141  	expr, t, _, _, err := transpileToExpr(n.Children()[0], p, false)
   142  	return expr, t, err
   143  }