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 }