xref: /aosp_15_r20/build/soong/androidmk/parser/scope.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage parser
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport "strings"
18*333d2b36SAndroid Build Coastguard Worker
19*333d2b36SAndroid Build Coastguard Workertype Scope interface {
20*333d2b36SAndroid Build Coastguard Worker	Get(name string) string
21*333d2b36SAndroid Build Coastguard Worker	Set(name, value string)
22*333d2b36SAndroid Build Coastguard Worker	Call(name string, args []string) []string
23*333d2b36SAndroid Build Coastguard Worker	SetFunc(name string, f func([]string) []string)
24*333d2b36SAndroid Build Coastguard Worker}
25*333d2b36SAndroid Build Coastguard Worker
26*333d2b36SAndroid Build Coastguard Workertype scope struct {
27*333d2b36SAndroid Build Coastguard Worker	variables map[string]string
28*333d2b36SAndroid Build Coastguard Worker	functions map[string]func([]string) []string
29*333d2b36SAndroid Build Coastguard Worker	parent    Scope
30*333d2b36SAndroid Build Coastguard Worker}
31*333d2b36SAndroid Build Coastguard Worker
32*333d2b36SAndroid Build Coastguard Workerfunc (s *scope) Get(name string) string {
33*333d2b36SAndroid Build Coastguard Worker	if val, ok := s.variables[name]; ok {
34*333d2b36SAndroid Build Coastguard Worker		return val
35*333d2b36SAndroid Build Coastguard Worker	} else if s.parent != nil {
36*333d2b36SAndroid Build Coastguard Worker		return s.parent.Get(name)
37*333d2b36SAndroid Build Coastguard Worker	} else if val, ok := builtinScope[name]; ok {
38*333d2b36SAndroid Build Coastguard Worker		return val
39*333d2b36SAndroid Build Coastguard Worker	} else {
40*333d2b36SAndroid Build Coastguard Worker		return "<'" + name + "' unset>"
41*333d2b36SAndroid Build Coastguard Worker	}
42*333d2b36SAndroid Build Coastguard Worker}
43*333d2b36SAndroid Build Coastguard Worker
44*333d2b36SAndroid Build Coastguard Workerfunc (s *scope) Set(name, value string) {
45*333d2b36SAndroid Build Coastguard Worker	s.variables[name] = value
46*333d2b36SAndroid Build Coastguard Worker}
47*333d2b36SAndroid Build Coastguard Worker
48*333d2b36SAndroid Build Coastguard Workerfunc (s *scope) Call(name string, args []string) []string {
49*333d2b36SAndroid Build Coastguard Worker	if f, ok := s.functions[name]; ok {
50*333d2b36SAndroid Build Coastguard Worker		return f(args)
51*333d2b36SAndroid Build Coastguard Worker	}
52*333d2b36SAndroid Build Coastguard Worker
53*333d2b36SAndroid Build Coastguard Worker	return []string{"<func:'" + name + "' unset>"}
54*333d2b36SAndroid Build Coastguard Worker}
55*333d2b36SAndroid Build Coastguard Worker
56*333d2b36SAndroid Build Coastguard Workerfunc (s *scope) SetFunc(name string, f func([]string) []string) {
57*333d2b36SAndroid Build Coastguard Worker	s.functions[name] = f
58*333d2b36SAndroid Build Coastguard Worker}
59*333d2b36SAndroid Build Coastguard Worker
60*333d2b36SAndroid Build Coastguard Workerfunc NewScope(parent Scope) Scope {
61*333d2b36SAndroid Build Coastguard Worker	return &scope{
62*333d2b36SAndroid Build Coastguard Worker		variables: make(map[string]string),
63*333d2b36SAndroid Build Coastguard Worker		functions: make(map[string]func([]string) []string),
64*333d2b36SAndroid Build Coastguard Worker		parent:    parent,
65*333d2b36SAndroid Build Coastguard Worker	}
66*333d2b36SAndroid Build Coastguard Worker}
67*333d2b36SAndroid Build Coastguard Worker
68*333d2b36SAndroid Build Coastguard Workervar builtinScope map[string]string
69*333d2b36SAndroid Build Coastguard Worker
70*333d2b36SAndroid Build Coastguard Workerfunc init() {
71*333d2b36SAndroid Build Coastguard Worker	builtinScope := make(map[string]string)
72*333d2b36SAndroid Build Coastguard Worker	builtinScope[builtinDollar] = "$"
73*333d2b36SAndroid Build Coastguard Worker}
74*333d2b36SAndroid Build Coastguard Worker
75*333d2b36SAndroid Build Coastguard Workerfunc (v Variable) EvalFunction(scope Scope) ([]string, bool) {
76*333d2b36SAndroid Build Coastguard Worker	f := v.Name.SplitN(" \t", 2)
77*333d2b36SAndroid Build Coastguard Worker	if len(f) > 1 && f[0].Const() {
78*333d2b36SAndroid Build Coastguard Worker		fname := f[0].Value(nil)
79*333d2b36SAndroid Build Coastguard Worker		if isFunctionName(fname) {
80*333d2b36SAndroid Build Coastguard Worker			args := f[1].Split(",")
81*333d2b36SAndroid Build Coastguard Worker			argVals := make([]string, len(args))
82*333d2b36SAndroid Build Coastguard Worker			for i, a := range args {
83*333d2b36SAndroid Build Coastguard Worker				argVals[i] = a.Value(scope)
84*333d2b36SAndroid Build Coastguard Worker			}
85*333d2b36SAndroid Build Coastguard Worker
86*333d2b36SAndroid Build Coastguard Worker			if fname == "call" {
87*333d2b36SAndroid Build Coastguard Worker				return scope.Call(argVals[0], argVals[1:]), true
88*333d2b36SAndroid Build Coastguard Worker			} else {
89*333d2b36SAndroid Build Coastguard Worker				return []string{"UNSUPPORTED FUNCTION:" + fname + " " + strings.Join(argVals, " ")}, true
90*333d2b36SAndroid Build Coastguard Worker			}
91*333d2b36SAndroid Build Coastguard Worker		}
92*333d2b36SAndroid Build Coastguard Worker	}
93*333d2b36SAndroid Build Coastguard Worker
94*333d2b36SAndroid Build Coastguard Worker	return []string{""}, false
95*333d2b36SAndroid Build Coastguard Worker}
96*333d2b36SAndroid Build Coastguard Worker
97*333d2b36SAndroid Build Coastguard Workerfunc (v Variable) Value(scope Scope) string {
98*333d2b36SAndroid Build Coastguard Worker	if ret, ok := v.EvalFunction(scope); ok {
99*333d2b36SAndroid Build Coastguard Worker		if len(ret) > 1 {
100*333d2b36SAndroid Build Coastguard Worker			panic("Expected a single value, but instead got a list")
101*333d2b36SAndroid Build Coastguard Worker		}
102*333d2b36SAndroid Build Coastguard Worker		return ret[0]
103*333d2b36SAndroid Build Coastguard Worker	}
104*333d2b36SAndroid Build Coastguard Worker	if scope == nil {
105*333d2b36SAndroid Build Coastguard Worker		panic("Cannot take the value of a variable in a nil scope")
106*333d2b36SAndroid Build Coastguard Worker	}
107*333d2b36SAndroid Build Coastguard Worker	return scope.Get(v.Name.Value(scope))
108*333d2b36SAndroid Build Coastguard Worker}
109*333d2b36SAndroid Build Coastguard Worker
110*333d2b36SAndroid Build Coastguard Workerfunc toVariable(ms *MakeString) (Variable, bool) {
111*333d2b36SAndroid Build Coastguard Worker	if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
112*333d2b36SAndroid Build Coastguard Worker		return ms.Variables[0], true
113*333d2b36SAndroid Build Coastguard Worker	}
114*333d2b36SAndroid Build Coastguard Worker	return Variable{}, false
115*333d2b36SAndroid Build Coastguard Worker}
116