1// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package androidmk
16
17import (
18	"fmt"
19	"strings"
20
21	mkparser "android/soong/androidmk/parser"
22
23	bpparser "github.com/google/blueprint/parser"
24)
25
26func stringToStringValue(s string) bpparser.Expression {
27	return &bpparser.String{
28		Value: s,
29	}
30}
31
32func stringListToStringValueList(list []string) []bpparser.Expression {
33	valList := make([]bpparser.Expression, len(list))
34	for i, l := range list {
35		valList[i] = stringToStringValue(l)
36	}
37	return valList
38}
39
40func addValues(val1, val2 bpparser.Expression) (bpparser.Expression, error) {
41	if val1 == nil {
42		return val2, nil
43	}
44
45	if val1.Type() == bpparser.StringType && val2.Type() == bpparser.ListType {
46		val1 = &bpparser.List{
47			Values: []bpparser.Expression{val1},
48		}
49	} else if val2.Type() == bpparser.StringType && val1.Type() == bpparser.ListType {
50		val2 = &bpparser.List{
51			Values: []bpparser.Expression{val1},
52		}
53	} else if val1.Type() != val2.Type() {
54		return nil, fmt.Errorf("cannot add mismatched types")
55	}
56
57	return &bpparser.Operator{
58		Operator: '+',
59		Args:     [2]bpparser.Expression{val1, val2},
60	}, nil
61}
62
63func makeToStringExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
64	var val bpparser.Expression
65	var err error
66
67	if ms.Strings[0] != "" {
68		val = stringToStringValue(ms.Strings[0])
69	}
70
71	for i, s := range ms.Strings[1:] {
72		if ret, ok := ms.Variables[i].EvalFunction(file.scope); ok {
73			if len(ret) > 1 {
74				return nil, fmt.Errorf("Unexpected list value %s", ms.Dump())
75			}
76			val, err = addValues(val, stringToStringValue(ret[0]))
77		} else {
78			name, err := extractVariableName(ms.Variables[i].Name, file)
79			if err != nil {
80				return nil, err
81			}
82			tmp := &bpparser.Variable{
83				Name:  name,
84				Value: &bpparser.String{},
85			}
86
87			if tmp.Name == "TOP" {
88				if s[0] == '/' {
89					s = s[1:]
90				} else {
91					s = "." + s
92				}
93			} else {
94				val, err = addValues(val, tmp)
95				if err != nil {
96					return nil, err
97				}
98			}
99		}
100
101		if s != "" {
102			tmp := stringToStringValue(s)
103			val, err = addValues(val, tmp)
104			if err != nil {
105				return nil, err
106			}
107		}
108	}
109
110	return val, nil
111}
112
113func stringToListValue(s string) bpparser.Expression {
114	list := strings.Fields(s)
115	valList := make([]bpparser.Expression, len(list))
116	for i, l := range list {
117		valList[i] = &bpparser.String{
118			Value: l,
119		}
120	}
121	return &bpparser.List{
122		Values: valList,
123	}
124
125}
126
127func makeToListExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
128	fields := ms.Split(" \t")
129
130	var listOfListValues []bpparser.Expression
131
132	listValue := &bpparser.List{}
133
134	for _, f := range fields {
135		if len(f.Variables) == 1 && f.Strings[0] == "" && f.Strings[1] == "" {
136			if ret, ok := f.Variables[0].EvalFunction(file.scope); ok {
137				listValue.Values = append(listValue.Values, stringListToStringValueList(ret)...)
138			} else {
139				name, err := extractVariableName(f.Variables[0].Name, file)
140				if err != nil {
141					return nil, err
142				}
143				if name == "TOP" {
144					listValue.Values = append(listValue.Values, &bpparser.String{
145						Value: ".",
146					})
147				} else {
148					if len(listValue.Values) > 0 {
149						listOfListValues = append(listOfListValues, listValue)
150					}
151					listOfListValues = append(listOfListValues, &bpparser.Variable{
152						Name:  name,
153						Value: &bpparser.List{},
154					})
155					listValue = &bpparser.List{}
156				}
157			}
158		} else {
159			s, err := makeToStringExpression(f, file)
160			if err != nil {
161				return nil, err
162			}
163			if s == nil {
164				continue
165			}
166
167			listValue.Values = append(listValue.Values, s)
168		}
169	}
170
171	if len(listValue.Values) > 0 {
172		listOfListValues = append(listOfListValues, listValue)
173	}
174
175	if len(listOfListValues) == 0 {
176		return listValue, nil
177	}
178
179	val := listOfListValues[0]
180	for _, tmp := range listOfListValues[1:] {
181		var err error
182		val, err = addValues(val, tmp)
183		if err != nil {
184			return nil, err
185		}
186	}
187
188	return val, nil
189}
190
191func stringToBoolValue(s string) (bpparser.Expression, error) {
192	var b bool
193	s = strings.TrimSpace(s)
194	switch s {
195	case "true":
196		b = true
197	case "false", "":
198		b = false
199	case "-frtti": // HACK for LOCAL_RTTI_VALUE
200		b = true
201	default:
202		return nil, fmt.Errorf("unexpected bool value %s", s)
203	}
204	return &bpparser.Bool{
205		Value: b,
206	}, nil
207}
208
209func makeToBoolExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
210	if !ms.Const() {
211		if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
212			name, err := extractVariableName(ms.Variables[0].Name, file)
213			if err != nil {
214				return nil, err
215			}
216			return &bpparser.Variable{
217				Name:  name,
218				Value: &bpparser.Bool{},
219			}, nil
220		} else {
221			return nil, fmt.Errorf("non-const bool expression %s", ms.Dump())
222		}
223	}
224
225	return stringToBoolValue(ms.Value(nil))
226}
227
228func extractVariableName(name *mkparser.MakeString, file *bpFile) (string, error) {
229	if !name.Const() {
230		return "", fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
231	}
232
233	variableName := name.Value(nil)
234
235	if newName, ok := file.variableRenames[variableName]; ok {
236		variableName = newName
237	}
238
239	return variableName, nil
240}
241