| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package fidlgen_cpp |
| |
| import ( |
| "fmt" |
| "strings" |
| |
| "go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen" |
| ) |
| |
| // |
| // Combined logic for constant values and const declarations. |
| // |
| |
| type ConstantValue struct { |
| Natural string |
| Wire string |
| } |
| |
| func (cv ConstantValue) IsSet() bool { |
| return cv.Natural != "" && cv.Wire != "" |
| } |
| |
| func (cv ConstantValue) String() string { |
| switch currentVariant { |
| case noVariant: |
| fidlgen.TemplateFatalf( |
| "Called ConstantValue.String() on %s/%s when currentVariant isn't set.\n", |
| cv.Natural, cv.Wire) |
| case naturalVariant: |
| return string(cv.Natural) |
| case wireVariant: |
| return string(cv.Wire) |
| case unifiedVariant: |
| return string(cv.Natural) |
| } |
| panic("not reached") |
| } |
| |
| func (c *compiler) compileConstant(val fidlgen.Constant, t *Type, typ fidlgen.Type) ConstantValue { |
| switch val.Kind { |
| case fidlgen.IdentifierConstant: |
| n := c.compileNameVariants(val.Identifier) |
| return ConstantValue{Natural: n.Natural.String(), Wire: n.Wire.String()} |
| case fidlgen.LiteralConstant: |
| lit := c.compileLiteral(val.Literal, typ) |
| return ConstantValue{Natural: lit, Wire: lit} |
| case fidlgen.BinaryOperator: |
| return ConstantValue{ |
| Natural: fmt.Sprintf("static_cast<%s>(%s)", t.nameVariants.Natural, val.Value), |
| Wire: fmt.Sprintf("static_cast<%s>(%s)", t.nameVariants.Wire, val.Value), |
| } |
| // return ConstantValue{Natural: naturalVal, Wire: wireVal} |
| default: |
| panic(fmt.Sprintf("unknown constant kind: %v", val.Kind)) |
| } |
| } |
| |
| type Const struct { |
| Attributes |
| nameVariants |
| Extern bool |
| Decorator string |
| Type Type |
| Value ConstantValue |
| } |
| |
| func (Const) Kind() declKind { |
| return Kinds.Const |
| } |
| |
| var _ Kinded = (*Const)(nil) |
| var _ namespaced = (*Const)(nil) |
| |
| func (c *compiler) compileConst(val fidlgen.Const) Const { |
| n := c.compileNameVariants(val.Name) |
| v := Const{ |
| Attributes: Attributes{val.Attributes}, |
| nameVariants: n, |
| } |
| if val.Type.Kind == fidlgen.StringType { |
| v.Extern = true |
| v.Decorator = "const" |
| v.Type = Type{ |
| nameVariants: primitiveNameVariants("char*"), |
| } |
| v.Value = c.compileConstant(val.Value, nil, val.Type) |
| } else { |
| t := c.compileType(val.Type) |
| v.Extern = false |
| v.Decorator = "constexpr" |
| v.Type = t |
| v.Value = c.compileConstant(val.Value, &t, val.Type) |
| } |
| |
| return v |
| } |
| |
| func (c *compiler) compileLiteral(val fidlgen.Literal, typ fidlgen.Type) string { |
| switch val.Kind { |
| case fidlgen.StringLiteral: |
| return fmt.Sprintf("%q", val.Value) |
| case fidlgen.NumericLiteral: |
| if val.Value == "-9223372036854775808" || val.Value == "0x8000000000000000" { |
| // C++ only supports nonnegative literals and a value this large in absolute |
| // value cannot be represented as a nonnegative number in 64-bits. |
| return "(-9223372036854775807ll-1)" |
| } |
| // TODO(fxbug.dev/7810): Once we expose resolved constants for defaults, e.g. |
| // in structs, we will not need ignore hex and binary values. |
| if strings.HasPrefix(val.Value, "0x") || strings.HasPrefix(val.Value, "0b") { |
| return val.Value |
| } |
| |
| // float32 literals must be marked as such. |
| if strings.ContainsRune(val.Value, '.') { |
| if typ.Kind == fidlgen.PrimitiveType && typ.PrimitiveSubtype == fidlgen.Float32 { |
| return fmt.Sprintf("%sf", val.Value) |
| } else { |
| return val.Value |
| } |
| } |
| |
| if !strings.HasPrefix(val.Value, "-") { |
| return fmt.Sprintf("%su", val.Value) |
| } |
| return val.Value |
| case fidlgen.TrueLiteral: |
| return "true" |
| case fidlgen.FalseLiteral: |
| return "false" |
| case fidlgen.DefaultLiteral: |
| return "default" |
| default: |
| panic(fmt.Sprintf("unknown literal kind: %v", val.Kind)) |
| } |
| } |