1package main
2
3import (
4	"fmt"
5	"strings"
6
7	mkparser "android/soong/androidmk/parser"
8
9	bpparser "github.com/google/blueprint/parser"
10)
11
12func stringToStringValue(s string) *bpparser.Value {
13	return &bpparser.Value{
14		Type:        bpparser.String,
15		StringValue: s,
16	}
17}
18
19func addValues(val1, val2 *bpparser.Value) (*bpparser.Value, error) {
20	if val1 == nil {
21		return val2, nil
22	}
23
24	if val1.Type == bpparser.String && val2.Type == bpparser.List {
25		val1 = &bpparser.Value{
26			Type:      bpparser.List,
27			ListValue: []bpparser.Value{*val1},
28		}
29	} else if val2.Type == bpparser.String && val1.Type == bpparser.List {
30		val2 = &bpparser.Value{
31			Type:      bpparser.List,
32			ListValue: []bpparser.Value{*val1},
33		}
34	} else if val1.Type != val2.Type {
35		return nil, fmt.Errorf("cannot add mismatched types")
36	}
37
38	return &bpparser.Value{
39		Type: val1.Type,
40		Expression: &bpparser.Expression{
41			Operator: '+',
42			Args:     [2]bpparser.Value{*val1, *val2},
43		},
44	}, nil
45}
46
47func makeToStringExpression(ms *mkparser.MakeString, scope mkparser.Scope) (*bpparser.Value, error) {
48	var val *bpparser.Value
49	var err error
50
51	if ms.Strings[0] != "" {
52		val = stringToStringValue(ms.Strings[0])
53	}
54
55	for i, s := range ms.Strings[1:] {
56		if ret, ok := ms.Variables[i].EvalFunction(scope); ok {
57			val, err = addValues(val, stringToStringValue(ret))
58		} else {
59			name := ms.Variables[i].Name
60			if !name.Const() {
61				return nil, fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
62			}
63			tmp := &bpparser.Value{
64				Type:     bpparser.String,
65				Variable: name.Value(nil),
66			}
67
68			val, err = addValues(val, tmp)
69			if err != nil {
70				return nil, err
71			}
72		}
73
74		if s != "" {
75			tmp := stringToStringValue(s)
76			val, err = addValues(val, tmp)
77			if err != nil {
78				return nil, err
79			}
80		}
81	}
82
83	return val, nil
84}
85
86func stringToListValue(s string) *bpparser.Value {
87	list := strings.Fields(s)
88	valList := make([]bpparser.Value, len(list))
89	for i, l := range list {
90		valList[i] = bpparser.Value{
91			Type:        bpparser.String,
92			StringValue: l,
93		}
94	}
95	return &bpparser.Value{
96		Type:      bpparser.List,
97		ListValue: valList,
98	}
99
100}
101
102func makeToListExpression(ms *mkparser.MakeString, scope mkparser.Scope) (*bpparser.Value, error) {
103	fields := ms.Split(" \t")
104
105	var listOfListValues []*bpparser.Value
106
107	listValue := &bpparser.Value{
108		Type: bpparser.List,
109	}
110
111	for _, f := range fields {
112		if len(f.Variables) == 1 && f.Strings[0] == "" && f.Strings[1] == "" {
113			if ret, ok := f.Variables[0].EvalFunction(scope); ok {
114				listValue.ListValue = append(listValue.ListValue, bpparser.Value{
115					Type:        bpparser.String,
116					StringValue: ret,
117				})
118			} else {
119				// Variable by itself, variable is probably a list
120				if !f.Variables[0].Name.Const() {
121					return nil, fmt.Errorf("unsupported non-const variable name")
122				}
123				if len(listValue.ListValue) > 0 {
124					listOfListValues = append(listOfListValues, listValue)
125				}
126				listOfListValues = append(listOfListValues, &bpparser.Value{
127					Type:     bpparser.List,
128					Variable: f.Variables[0].Name.Value(nil),
129				})
130				listValue = &bpparser.Value{
131					Type: bpparser.List,
132				}
133			}
134		} else {
135			s, err := makeToStringExpression(f, scope)
136			if err != nil {
137				return nil, err
138			}
139			if s == nil {
140				continue
141			}
142
143			listValue.ListValue = append(listValue.ListValue, *s)
144		}
145	}
146
147	if len(listValue.ListValue) > 0 {
148		listOfListValues = append(listOfListValues, listValue)
149	}
150
151	if len(listOfListValues) == 0 {
152		return listValue, nil
153	}
154
155	val := listOfListValues[0]
156	for _, tmp := range listOfListValues[1:] {
157		var err error
158		val, err = addValues(val, tmp)
159		if err != nil {
160			return nil, err
161		}
162	}
163
164	return val, nil
165}
166
167func stringToBoolValue(s string) (*bpparser.Value, error) {
168	var b bool
169	s = strings.TrimSpace(s)
170	switch s {
171	case "true":
172		b = true
173	case "false", "":
174		b = false
175	case "-frtti": // HACK for LOCAL_RTTI_VALUE
176		b = true
177	default:
178		return nil, fmt.Errorf("unexpected bool value %s", s)
179	}
180	return &bpparser.Value{
181		Type:      bpparser.Bool,
182		BoolValue: b,
183	}, nil
184}
185
186func makeToBoolExpression(ms *mkparser.MakeString) (*bpparser.Value, error) {
187	if !ms.Const() {
188		if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
189			name := ms.Variables[0].Name
190			if !name.Const() {
191				return nil, fmt.Errorf("unsupported non-const variable name")
192			}
193			return &bpparser.Value{
194				Type:     bpparser.Bool,
195				Variable: name.Value(nil),
196			}, nil
197		} else {
198			return nil, fmt.Errorf("non-const bool expression %s", ms.Dump())
199		}
200	}
201
202	return stringToBoolValue(ms.Value(nil))
203}
204