blob: 5c58496347111354bb1876bf1a6d33484dd35951 [file] [log] [blame]
// 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"
)
// Namespaced is implemented by types that have a C++ namespace.
type Namespaced interface {
Namespace() Namespace
}
// During template processing this holds the current namespace.
var currentNamespace Namespace
// EnsureNamespace changes the current namespace to the one supplied and
// returns the C++ code required to switch to that namespace.
func EnsureNamespace(arg interface{}) string {
lines := []string{}
newNamespace := []string{}
switch v := arg.(type) {
case Namespaced:
newNamespace = []string(v.Namespace())
case string:
newNamespace = strings.Split(v, "::")
for len(newNamespace) > 0 && newNamespace[0] == "" {
newNamespace = newNamespace[1:]
}
default:
panic(fmt.Sprintf("Unexpected %T argument to EnsureNamespace", arg))
}
// Copy the namespaces
new := make([]string, len(newNamespace))
copy(new, newNamespace)
current := make([]string, len(currentNamespace))
copy(current, currentNamespace)
// Remove common prefix
for len(new) > 0 && len(current) > 0 && new[0] == current[0] {
new = new[1:]
current = current[1:]
}
// Leave the current namespace
for i := len(current) - 1; i >= 0; i-- {
lines = append(lines, fmt.Sprintf("} // namespace %s", current[i]))
}
// Enter thew new namespace
for i := 0; i < len(new); i++ {
lines = append(lines, fmt.Sprintf("namespace %s {", new[i]))
}
// Update the current namespace variable
currentNamespace = Namespace(newNamespace)
return strings.Join(lines, "\n")
}
// During template processing this holds the stack of pushed & popped templates
var namespaceStack = []Namespace{}
func PushNamespace() string {
namespaceStack = append(namespaceStack, currentNamespace)
return ""
}
func PopNamespace() string {
last := len(namespaceStack) - 1
ns := namespaceStack[last]
namespaceStack = namespaceStack[:last]
return EnsureNamespace(ns)
}
func EndOfFile() string {
if len(namespaceStack) != 0 {
panic("The namespace stack isn't empty, there's a PopNamespace missing somewhere")
}
return EnsureNamespace("::")
}