Merge "androidmk: make class+suffix into generic prefix" into master-soong
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 55e47cb..8d7025c 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -74,7 +74,7 @@
 }
 
 var rewriteProperties = map[string]struct {
-	f func(file *bpFile, value *mkparser.MakeString, append bool, class, suffix string) error
+	f func(file *bpFile, prefix string, value *mkparser.MakeString, append bool) error
 }{
 	"LOCAL_C_INCLUDES":            {localIncludeDirs},
 	"LOCAL_EXPORT_C_INCLUDE_DIRS": {exportIncludeDirs},
@@ -191,8 +191,7 @@
 	return local, global, nil
 }
 
-func localIncludeDirs(file *bpFile, value *mkparser.MakeString, appendVariable bool,
-	class, suffix string) error {
+func localIncludeDirs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error {
 	val, err := makeVariableToBlueprint(file, value, bpparser.List)
 	if err != nil {
 		return err
@@ -204,14 +203,14 @@
 	}
 
 	if len(global.ListValue) > 0 || global.Expression != nil || global.Variable != "" {
-		err = setVariable(file, appendVariable, "include_dirs", global, true, class, suffix)
+		err = setVariable(file, appendVariable, prefix, "include_dirs", global, true)
 		if err != nil {
 			return err
 		}
 	}
 
 	if len(local.ListValue) > 0 || local.Expression != nil || local.Variable != "" {
-		err = setVariable(file, appendVariable, "local_include_dirs", local, true, class, suffix)
+		err = setVariable(file, appendVariable, prefix, "local_include_dirs", local, true)
 		if err != nil {
 			return err
 		}
@@ -220,9 +219,7 @@
 	return nil
 }
 
-func exportIncludeDirs(file *bpFile, value *mkparser.MakeString, appendVariable bool,
-	class, suffix string) error {
-
+func exportIncludeDirs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error {
 	val, err := makeVariableToBlueprint(file, value, bpparser.List)
 	if err != nil {
 		return err
@@ -234,7 +231,7 @@
 	}
 
 	if len(local.ListValue) > 0 || local.Expression != nil || local.Variable != "" {
-		err = setVariable(file, appendVariable, "export_include_dirs", local, true, class, suffix)
+		err = setVariable(file, appendVariable, prefix, "export_include_dirs", local, true)
 		if err != nil {
 			return err
 		}
@@ -244,7 +241,7 @@
 	// Add any paths that could not be converted to local relative paths to export_include_dirs
 	// anyways, they will cause an error if they don't exist and can be fixed manually.
 	if len(global.ListValue) > 0 || global.Expression != nil || global.Variable != "" {
-		err = setVariable(file, appendVariable, "export_include_dirs", global, true, class, suffix)
+		err = setVariable(file, appendVariable, prefix, "export_include_dirs", global, true)
 		if err != nil {
 			return err
 		}
@@ -253,7 +250,7 @@
 	return nil
 }
 
-func stem(file *bpFile, value *mkparser.MakeString, appendVariable bool, class, suffix string) error {
+func stem(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error {
 	val, err := makeVariableToBlueprint(file, value, bpparser.String)
 	if err != nil {
 		return err
@@ -266,47 +263,58 @@
 		val = &val.Expression.Args[1]
 	}
 
-	return setVariable(file, appendVariable, varName, val, true, class, suffix)
+	return setVariable(file, appendVariable, prefix, varName, val, true)
 }
 
 var deleteProperties = map[string]struct{}{
 	"LOCAL_CPP_EXTENSION": struct{}{},
 }
 
-var propertySuffixes = []struct {
-	suffix string
-	class  string
-}{
-	{"arm", "arch"},
-	{"arm64", "arch"},
-	{"mips", "arch"},
-	{"mips64", "arch"},
-	{"x86", "arch"},
-	{"x86_64", "arch"},
-	{"32", "multilib"},
-	{"64", "multilib"},
+var propertyPrefixes = map[string]string{
+	"arm":    "arch.arm",
+	"arm64":  "arm.arm64",
+	"mips":   "arch.mips",
+	"mips64": "arch.mips64",
+	"x86":    "arch.x86",
+	"x86_64": "arch.x86_64",
+	"32":     "multilib.lib32",
+	"64":     "multilib.lib64",
 }
 
-var propertySuffixTranslations = map[string]string{
-	"32": "lib32",
-	"64": "lib64",
-}
-
-var conditionalTranslations = map[string]struct {
-	class  string
-	suffix string
-}{
-	"($(HOST_OS),darwin)":   {"target", "darwin"},
-	"($(HOST_OS), darwin)":  {"target", "darwin"},
-	"($(HOST_OS),windows)":  {"target", "windows"},
-	"($(HOST_OS), windows)": {"target", "windows"},
-	"($(HOST_OS),linux)":    {"target", "linux"},
-	"($(HOST_OS), linux)":   {"target", "linux"},
-	"($(BUILD_OS),darwin)":  {"target", "darwin"},
-	"($(BUILD_OS), darwin)": {"target", "darwin"},
-	"($(BUILD_OS),linux)":   {"target", "linux"},
-	"($(BUILD_OS), linux)":  {"target", "linux"},
-	"USE_MINGW":             {"target", "windows"},
+var conditionalTranslations = map[string]map[bool]string{
+	"($(HOST_OS),darwin)": {
+		true:  "target.darwin",
+		false: "target.not_darwin"},
+	"($(HOST_OS), darwin)": {
+		true:  "target.darwin",
+		false: "target.not_darwin"},
+	"($(HOST_OS),windows)": {
+		true:  "target.windows",
+		false: "target.not_windows"},
+	"($(HOST_OS), windows)": {
+		true:  "target.windows",
+		false: "target.not_windows"},
+	"($(HOST_OS),linux)": {
+		true:  "target.linux",
+		false: "target.not_linux"},
+	"($(HOST_OS), linux)": {
+		true:  "target.linux",
+		false: "target.not_linux"},
+	"($(BUILD_OS),darwin)": {
+		true:  "target.darwin",
+		false: "target.not_darwin"},
+	"($(BUILD_OS), darwin)": {
+		true:  "target.darwin",
+		false: "target.not_darwin"},
+	"($(BUILD_OS),linux)": {
+		true:  "target.linux",
+		false: "target.not_linux"},
+	"($(BUILD_OS), linux)": {
+		true:  "target.linux",
+		false: "target.not_linux"},
+	"USE_MINGW": {
+		true:  "target.windows",
+		false: "target.not_windows"},
 }
 
 func mydir(args []string) string {
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index b818230..735a240 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -188,34 +188,23 @@
 	}
 
 	name := assignment.Name.Value(nil)
-	suffix := ""
-	class := ""
+	prefix := ""
 
 	if strings.HasPrefix(name, "LOCAL_") {
-		for _, v := range propertySuffixes {
-			s, c := v.suffix, v.class
-			if strings.HasSuffix(name, "_"+s) {
-				name = strings.TrimSuffix(name, "_"+s)
-				suffix = s
-				if s, ok := propertySuffixTranslations[s]; ok {
-					suffix = s
-				}
-				class = c
+		for k, v := range propertyPrefixes {
+			if strings.HasSuffix(name, "_"+k) {
+				name = strings.TrimSuffix(name, "_"+k)
+				prefix = v
 				break
 			}
 		}
 
 		if c != nil {
-			if class != "" {
-				file.errorf(assignment, "suffix assignment inside conditional, skipping conditional")
+			if prefix != "" {
+				file.errorf(assignment, "prefix assignment inside conditional, skipping conditional")
 			} else {
-				if v, ok := conditionalTranslations[c.cond]; ok {
-					class = v.class
-					suffix = v.suffix
-					if !c.eq {
-						suffix = "not_" + suffix
-					}
-				} else {
+				var ok bool
+				if prefix, ok = conditionalTranslations[c.cond][c.eq]; !ok {
 					panic("unknown conditional")
 				}
 			}
@@ -237,10 +226,10 @@
 		var val *bpparser.Value
 		val, err = makeVariableToBlueprint(file, assignment.Value, prop.ValueType)
 		if err == nil {
-			err = setVariable(file, appendVariable, prop.string, val, true, class, suffix)
+			err = setVariable(file, appendVariable, prefix, prop.string, val, true)
 		}
 	} else if prop, ok := rewriteProperties[name]; ok {
-		err = prop.f(file, assignment.Value, appendVariable, class, suffix)
+		err = prop.f(file, prefix, assignment.Value, appendVariable)
 	} else if _, ok := deleteProperties[name]; ok {
 		return
 	} else {
@@ -261,7 +250,7 @@
 		default:
 			var val *bpparser.Value
 			val, err = makeVariableToBlueprint(file, assignment.Value, bpparser.List)
-			err = setVariable(file, appendVariable, name, val, false, class, suffix)
+			err = setVariable(file, appendVariable, prefix, name, val, false)
 		}
 	}
 	if err != nil {
@@ -274,38 +263,38 @@
 		return
 	}
 
-	if v, ok := conditionalTranslations[c.cond]; ok {
-		class := v.class
-		suffix := v.suffix
-		disabledSuffix := v.suffix
-		if !c.eq {
-			suffix = "not_" + suffix
-		} else {
-			disabledSuffix = "not_" + disabledSuffix
-		}
+	if _, ok := conditionalTranslations[c.cond]; !ok {
+		panic("unknown conditional " + c.cond)
+	}
 
-		// Hoist all properties inside the condtional up to the top level
-		file.module.Properties = file.localAssignments[class+"___"+suffix].Value.MapValue
-		file.module.Properties = append(file.module.Properties, file.localAssignments[class])
-		file.localAssignments[class+"___"+suffix].Value.MapValue = nil
-		for i := range file.localAssignments[class].Value.MapValue {
-			if file.localAssignments[class].Value.MapValue[i].Name.Name == suffix {
-				file.localAssignments[class].Value.MapValue =
-					append(file.localAssignments[class].Value.MapValue[:i],
-						file.localAssignments[class].Value.MapValue[i+1:]...)
-			}
-		}
+	prefix := conditionalTranslations[c.cond][c.eq]
+	disabledPrefix := conditionalTranslations[c.cond][!c.eq]
 
-		// Create a fake assignment with enabled = false
-		val, err := makeVariableToBlueprint(file, mkparser.SimpleMakeString("true", file.pos), bpparser.Bool)
-		if err == nil {
-			err = setVariable(file, false, "disabled", val, true, class, disabledSuffix)
+	names := strings.Split(prefix, ".")
+	if len(names) != 2 {
+		panic("expected class.type")
+	}
+	class := names[0]
+	typ := names[1]
+	classProp := file.localAssignments[class]
+
+	// Hoist all properties inside the condtional up to the top level
+	file.module.Properties = file.localAssignments[prefix].Value.MapValue
+	file.module.Properties = append(file.module.Properties, classProp)
+	file.localAssignments[prefix].Value.MapValue = nil
+	for i := range classProp.Value.MapValue {
+		if classProp.Value.MapValue[i].Name.Name == typ {
+			classProp.Value.MapValue = append(classProp.Value.MapValue[:i], classProp.Value.MapValue[i+1:]...)
 		}
-		if err != nil {
-			file.errorf(directive, err.Error())
-		}
-	} else {
-		panic("unknown conditional")
+	}
+
+	// Create a fake assignment with enabled = false
+	val, err := makeVariableToBlueprint(file, mkparser.SimpleMakeString("true", file.pos), bpparser.Bool)
+	if err == nil {
+		err = setVariable(file, false, disabledPrefix, "disabled", val, true)
+	}
+	if err != nil {
+		file.errorf(directive, err.Error())
 	}
 }
 
@@ -347,19 +336,17 @@
 	return exp, nil
 }
 
-func setVariable(file *bpFile, plusequals bool, name string, value *bpparser.Value, local bool,
-	class string, suffix string) error {
+func setVariable(file *bpFile, plusequals bool, prefix, name string, value *bpparser.Value, local bool) error {
+
+	if prefix != "" {
+		name = prefix + "." + name
+	}
 
 	pos := file.pos
 
 	var oldValue *bpparser.Value
 	if local {
-		var oldProp *bpparser.Property
-		if class != "" {
-			oldProp = file.localAssignments[name+"___"+class+"___"+suffix]
-		} else {
-			oldProp = file.localAssignments[name]
-		}
+		oldProp := file.localAssignments[name]
 		if oldProp != nil {
 			oldValue = &oldProp.Value
 		}
@@ -375,50 +362,35 @@
 			}
 			val.Expression.Pos = pos
 			*oldValue = *val
-		} else if class == "" {
+		} else {
+			names := strings.Split(name, ".")
+			container := &file.module.Properties
+
+			for i, n := range names[:len(names)-1] {
+				fqn := strings.Join(names[0:i+1], ".")
+				prop := file.localAssignments[fqn]
+				if prop == nil {
+					prop = &bpparser.Property{
+						Name: bpparser.Ident{Name: n, Pos: pos},
+						Pos:  pos,
+						Value: bpparser.Value{
+							Type:     bpparser.Map,
+							MapValue: []*bpparser.Property{},
+						},
+					}
+					file.localAssignments[fqn] = prop
+					*container = append(*container, prop)
+				}
+				container = &prop.Value.MapValue
+			}
+
 			prop := &bpparser.Property{
-				Name:  bpparser.Ident{Name: name, Pos: pos},
+				Name:  bpparser.Ident{Name: names[len(names)-1], Pos: pos},
 				Pos:   pos,
 				Value: *value,
 			}
 			file.localAssignments[name] = prop
-			file.module.Properties = append(file.module.Properties, prop)
-		} else {
-			classProp := file.localAssignments[class]
-			if classProp == nil {
-				classProp = &bpparser.Property{
-					Name: bpparser.Ident{Name: class, Pos: pos},
-					Pos:  pos,
-					Value: bpparser.Value{
-						Type:     bpparser.Map,
-						MapValue: []*bpparser.Property{},
-					},
-				}
-				file.localAssignments[class] = classProp
-				file.module.Properties = append(file.module.Properties, classProp)
-			}
-
-			suffixProp := file.localAssignments[class+"___"+suffix]
-			if suffixProp == nil {
-				suffixProp = &bpparser.Property{
-					Name: bpparser.Ident{Name: suffix, Pos: pos},
-					Pos:  pos,
-					Value: bpparser.Value{
-						Type:     bpparser.Map,
-						MapValue: []*bpparser.Property{},
-					},
-				}
-				file.localAssignments[class+"___"+suffix] = suffixProp
-				classProp.Value.MapValue = append(classProp.Value.MapValue, suffixProp)
-			}
-
-			prop := &bpparser.Property{
-				Name:  bpparser.Ident{Name: name, Pos: pos},
-				Pos:   pos,
-				Value: *value,
-			}
-			file.localAssignments[class+"___"+suffix+"___"+name] = prop
-			suffixProp.Value.MapValue = append(suffixProp.Value.MapValue, prop)
+			*container = append(*container, prop)
 		}
 	} else {
 		if oldValue != nil && plusequals {