[fidlgen] move name contexts to common library

The Dart bindings generator's name context logic has been very useful
enabling fine-grained reserved name handling. As we're moving to
start transforming names in the LLCPP backend it would be nice to be
able to share that logic so this moves that from fidlgen_dart into the
fidlgen package.

Change-Id: Ia296aa281d1377d1cebfb291d590427ccd6f541e
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/514780
Commit-Queue: Ian McKellar <ianloic@google.com>
Fuchsia-Auto-Submit: Ian McKellar <ianloic@google.com>
Reviewed-by: Mitchell Kember <mkember@google.com>
diff --git a/tools/fidl/fidlgen_dart/codegen/ir.go b/tools/fidl/fidlgen_dart/codegen/ir.go
index 7d746ed..2e82d0e 100644
--- a/tools/fidl/fidlgen_dart/codegen/ir.go
+++ b/tools/fidl/fidlgen_dart/codegen/ir.go
@@ -211,38 +211,40 @@
 	Unions      []Union
 }
 
-type context map[string]bool
+func changeName(name string) string {
+	return name + "$"
+}
 
 var (
 	// Name of a bits member
-	bitsMemberContext = make(context)
+	bitsMemberContext = fidlgen.NewNameContext(changeName)
 	// Name of an enum member
-	enumMemberContext = make(context)
+	enumMemberContext = fidlgen.NewNameContext(changeName)
 	// Name of a struct member
-	structMemberContext = make(context)
+	structMemberContext = fidlgen.NewNameContext(changeName)
 	// Name of a table member
-	tableMemberContext = make(context)
+	tableMemberContext = fidlgen.NewNameContext(changeName)
 	// Name of a union member
-	unionMemberContext = make(context)
+	unionMemberContext = fidlgen.NewNameContext(changeName)
 	// Tag of a union member
-	unionMemberTagContext = make(context)
+	unionMemberTagContext = fidlgen.NewNameContext(changeName)
 	// Name of a constant
-	constantContext = make(context)
+	constantContext = fidlgen.NewNameContext(changeName)
 	// Name of a top-level declaration (other than a constant)
-	declarationContext = make(context)
+	declarationContext = fidlgen.NewNameContext(changeName)
 	// Name of a method
-	methodContext = make(context)
+	methodContext = fidlgen.NewNameContext(changeName)
 	// Everywhere
 )
 
 func init() {
-	var allContexts = []context{
+	var allContexts = []fidlgen.NameContext{
 		enumMemberContext, structMemberContext, tableMemberContext,
 		unionMemberContext, unionMemberTagContext, constantContext,
 		declarationContext, methodContext, bitsMemberContext,
 	}
 
-	var reservedWords = map[string][]context{
+	fidlgen.ReserveNames(map[string][]fidlgen.NameContext{
 		"assert":       allContexts,
 		"async":        allContexts,
 		"await":        allContexts,
@@ -297,19 +299,7 @@
 		"while":        allContexts,
 		"with":         allContexts,
 		"yield":        allContexts,
-	}
-	for word, ctxs := range reservedWords {
-		for _, ctx := range ctxs {
-			ctx[word] = true
-		}
-	}
-}
-
-func (ctx context) changeIfReserved(str string) string {
-	if ctx[str] {
-		return str + "$"
-	}
-	return str
+	})
 }
 
 var declForPrimitiveType = map[fidlgen.PrimitiveSubtype]string{
@@ -527,39 +517,39 @@
 	return t
 }
 
-func (c *compiler) compileUpperCamelIdentifier(val fidlgen.Identifier, context context) string {
-	return context.changeIfReserved(fidlgen.ToUpperCamelCase(string(val)))
+func (c *compiler) compileUpperCamelIdentifier(val fidlgen.Identifier, context fidlgen.NameContext) string {
+	return context.ChangeIfReserved(fidlgen.ToUpperCamelCase(string(val)))
 }
 
-func (c *compiler) compileLowerCamelIdentifier(val fidlgen.Identifier, context context) string {
-	return context.changeIfReserved(fidlgen.ToLowerCamelCase(string(val)))
+func (c *compiler) compileLowerCamelIdentifier(val fidlgen.Identifier, context fidlgen.NameContext) string {
+	return context.ChangeIfReserved(fidlgen.ToLowerCamelCase(string(val)))
 }
 
-func (c *compiler) compileCompoundIdentifier(val fidlgen.CompoundIdentifier, context context) string {
+func (c *compiler) compileCompoundIdentifier(val fidlgen.CompoundIdentifier, context fidlgen.NameContext) string {
 	strs := []string{}
 	if c.inExternalLibrary(val) {
 		strs = append(strs, libraryPrefix(val.Library))
 	}
-	strs = append(strs, context.changeIfReserved(string(val.Name)))
+	strs = append(strs, context.ChangeIfReserved(string(val.Name)))
 	if val.Member != "" {
-		strs = append(strs, context.changeIfReserved(string(val.Member)))
+		strs = append(strs, context.ChangeIfReserved(string(val.Member)))
 	}
 	return strings.Join(strs, ".")
 }
 
-func (c *compiler) compileUpperCamelCompoundIdentifier(val fidlgen.CompoundIdentifier, ext string, context context) string {
+func (c *compiler) compileUpperCamelCompoundIdentifier(val fidlgen.CompoundIdentifier, ext string, context fidlgen.NameContext) string {
 	str := fidlgen.ToUpperCamelCase(string(val.Name)) + ext
 	val.Name = fidlgen.Identifier(str)
 	return c.compileCompoundIdentifier(val, context)
 }
 
-func (c *compiler) compileLowerCamelCompoundIdentifier(val fidlgen.CompoundIdentifier, ext string, context context) string {
+func (c *compiler) compileLowerCamelCompoundIdentifier(val fidlgen.CompoundIdentifier, ext string, context fidlgen.NameContext) string {
 	str := fidlgen.ToLowerCamelCase(string(val.Name)) + ext
 	val.Name = fidlgen.Identifier(str)
 	return c.compileCompoundIdentifier(val, context)
 }
 
-func (c *compiler) compileConstantIdentifier(val fidlgen.CompoundIdentifier, context context) string {
+func (c *compiler) compileConstantIdentifier(val fidlgen.CompoundIdentifier, context fidlgen.NameContext) string {
 	if val.Member != "" {
 		// val.Name here is the type.
 		// Format: Type.memberIdentifier
diff --git a/tools/fidl/lib/fidlgen/BUILD.gn b/tools/fidl/lib/fidlgen/BUILD.gn
index ccb26e6..ba2aa007 100644
--- a/tools/fidl/lib/fidlgen/BUILD.gn
+++ b/tools/fidl/lib/fidlgen/BUILD.gn
@@ -10,6 +10,7 @@
     "formatter.go",
     "identifiers.go",
     "lazywriter.go",
+    "name_context.go",
     "names.go",
     "strings.go",
     "templates.go",
diff --git a/tools/fidl/lib/fidlgen/name_context.go b/tools/fidl/lib/fidlgen/name_context.go
new file mode 100644
index 0000000..4393efa
--- /dev/null
+++ b/tools/fidl/lib/fidlgen/name_context.go
@@ -0,0 +1,38 @@
+// 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
+
+type NameChanger func(string) string
+type NameContext struct {
+	reserved map[string]struct{}
+	changer  NameChanger
+}
+
+func NewNameContext(changer NameChanger) NameContext {
+	return NameContext{
+		reserved: make(map[string]struct{}),
+		changer:  changer,
+	}
+}
+
+func ReserveNames(names map[string][]NameContext) {
+	for name, contexts := range names {
+		for _, context := range contexts {
+			context.reserved[name] = struct{}{}
+		}
+	}
+}
+
+func (c *NameContext) IsReserved(name string) bool {
+	_, ok := c.reserved[name]
+	return ok
+}
+
+func (c *NameContext) ChangeIfReserved(name string) string {
+	if c.IsReserved(name) {
+		return c.changer(name)
+	}
+	return name
+}