github.com/gotranspile/cxgo@v0.3.7/macros.go (about)

     1  package cxgo
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/gotranspile/cxgo/types"
     6  	"sort"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"modernc.org/cc/v3"
    11  )
    12  
    13  func (g *translator) convertValue(v cc.Value) Expr {
    14  	switch v := v.(type) {
    15  	case cc.Int64Value:
    16  		return cIntLit(int64(v))
    17  	case cc.Uint64Value:
    18  		return cUintLit(uint64(v))
    19  	case cc.Float32Value:
    20  		return FloatLit{val: float64(v)}
    21  	case cc.Float64Value:
    22  		return FloatLit{val: float64(v)}
    23  	case cc.StringValue:
    24  		e, err := g.parseCStringLit(string(v))
    25  		if err != nil {
    26  			panic(err)
    27  		}
    28  		return e
    29  	default:
    30  		panic(fmt.Errorf("unsupported value type: %T", v))
    31  	}
    32  }
    33  
    34  func (g *translator) convertMacros(ast *cc.AST) []CDecl {
    35  	type macro struct {
    36  		name string
    37  		m    *cc.Macro
    38  	}
    39  	var arr []macro
    40  	for name, mc := range ast.Macros {
    41  		if !g.inCurFile(mc) {
    42  			continue
    43  		}
    44  		if mc.IsFnLike() {
    45  			continue // we don't support function macros yet
    46  		}
    47  		if len(mc.ReplacementTokens()) == 0 {
    48  			continue // no value
    49  		}
    50  		arr = append(arr, macro{name.String(), mc})
    51  	}
    52  	sort.Slice(arr, func(i, j int) bool {
    53  		return arr[i].m.Position().Offset < arr[j].m.Position().Offset
    54  	})
    55  	var decls []CDecl
    56  	for _, mc := range arr {
    57  		if val := g.evalMacro(mc.m, ast); val != nil {
    58  			typ := val.CType(nil)
    59  			id := types.NewIdent(mc.name, typ)
    60  			decls = append(decls, &CVarDecl{Const: true, CVarSpec: CVarSpec{
    61  				g: g, Type: typ,
    62  				Names: []*types.Ident{id},
    63  				Inits: []Expr{val},
    64  			}})
    65  		}
    66  	}
    67  	return decls
    68  }
    69  
    70  func (g *translator) evalMacro(m *cc.Macro, ast *cc.AST) Expr {
    71  	toks := m.ReplacementTokens()
    72  	if len(toks) != 1 {
    73  		return evalMacro2(m, ast)
    74  	}
    75  
    76  	src := strings.TrimSpace(toks[0].Src.String())
    77  	if len(src) == 0 {
    78  		return nil
    79  	}
    80  
    81  	if src[0] == '"' {
    82  		if s, err := strconv.Unquote(src); err == nil {
    83  			if l, err := g.parseCStringLit(s); err == nil {
    84  				return l
    85  			}
    86  		}
    87  	} else {
    88  		if l, err := parseCIntLit(src); err == nil {
    89  			return l
    90  		}
    91  		if l, err := parseCFloatLit(src); err == nil {
    92  			return l
    93  		}
    94  	}
    95  
    96  	return evalMacro2(m, ast)
    97  }
    98  
    99  func evalMacro2(m *cc.Macro, ast *cc.AST) Expr {
   100  	op, err := ast.Eval(m)
   101  	if err != nil {
   102  		return nil
   103  	}
   104  
   105  	switch x := op.Value().(type) {
   106  	case cc.Int64Value:
   107  		return cIntLit(int64(x))
   108  	case cc.Uint64Value:
   109  		return cUintLit(uint64(x))
   110  	default:
   111  		return nil
   112  	}
   113  }