blob: 0925765e446593289eb7992794e89e8a115be183 [file] [log] [blame]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09001package main
2
3import (
4 "bytes"
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +09005 "fmt"
Shinichiro Hamajie57b5692015-03-30 23:16:47 +09006 "regexp"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09007 "strings"
8)
9
10type Rule struct {
Fumitoshi Ukaiad720602015-03-31 10:29:59 +090011 output string
12 inputs []string
13 cmds []string
14 filename string
15 lineno int
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +090016 cmdLineno int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090017}
18
19type EvalResult struct {
20 vars map[string]string
21 rules []*Rule
22 refs map[string]bool
23}
24
25type Evaluator struct {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090026 outVars map[string]string
27 outRules []*Rule
28 refs map[string]bool
29 vars map[string]string
30 curRule *Rule
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090031
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090032 funcs map[string]Func
33
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090034 filename string
35 lineno int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090036}
37
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090038func newEvaluator(vars map[string]string) *Evaluator {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090039 return &Evaluator{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090040 outVars: make(map[string]string),
41 refs: make(map[string]bool),
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090042 vars: vars,
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090043 funcs: map[string]Func{
44 "wildcard": funcWildcard,
45 "shell": funcShell,
46 "warning": funcWarning,
47 },
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090048 }
49}
50
51func (ev *Evaluator) evalFunction(ex string) (string, bool) {
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090052 i := strings.IndexAny(ex, " \t")
53 if i < 0 {
54 return "", false
55 }
56 cmd := strings.TrimSpace(ex[:i])
57 args := strings.TrimLeft(ex[i+1:], " \t")
58 if f, ok := ev.funcs[cmd]; ok {
59 return f(ev, args), true
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090060 }
61 return "", false
62}
63
64func (ev *Evaluator) evalExprSlice(ex string, term byte) (string, int) {
65 var buf bytes.Buffer
66 i := 0
67 for i < len(ex) && ex[i] != term {
68 ch := ex[i]
69 i++
70 switch ch {
71 case '$':
72 if i >= len(ex) || ex[i] == term {
73 continue
74 }
75
76 var varname string
77 switch ex[i] {
78 case '@':
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090079 buf.WriteString(ev.curRule.output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090080 i++
81 continue
Fumitoshi Ukaiad720602015-03-31 10:29:59 +090082 case '(', '{':
83 var cp byte = ')'
84 if ex[i] == '{' {
85 cp = '}'
86 }
87 v, j := ev.evalExprSlice(ex[i+1:], cp)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090088 i += j + 2
89 if r, done := ev.evalFunction(v); done {
90 buf.WriteString(r)
91 continue
92 }
93
94 varname = v
95 default:
96 varname = string(ex[i])
97 i++
98 }
99
100 value, present := ev.vars[varname]
101 if !present {
102 ev.refs[varname] = true
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900103 value = ev.outVars[varname]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900104 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900105 buf.WriteString(ev.evalExpr(value))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900106
107 default:
108 buf.WriteByte(ch)
109 }
110 }
111 return buf.String(), i
112}
113
114func (ev *Evaluator) evalExpr(ex string) string {
115 r, i := ev.evalExprSlice(ex, 0)
116 if len(ex) != i {
Fumitoshi Ukaiad720602015-03-31 10:29:59 +0900117 panic(fmt.Sprintf("Had a null character? %q, %d", ex, i))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900118 }
119 return r
120}
121
122func (ev *Evaluator) evalAssign(ast *AssignAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900123 ev.filename = ast.filename
124 ev.lineno = ast.lineno
125
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900126 lhs := ev.evalExpr(ast.lhs)
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900127 rhs := ast.evalRHS(ev, lhs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900128 Log("ASSIGN: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900129 ev.outVars[lhs] = rhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900130}
131
132func (ev *Evaluator) evalRule(ast *RuleAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900133 ev.filename = ast.filename
134 ev.lineno = ast.lineno
135
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900136 ev.curRule = &Rule{
Fumitoshi Ukaiad720602015-03-31 10:29:59 +0900137 filename: ast.filename,
138 lineno: ast.lineno,
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900139 cmdLineno: ast.cmdLineno,
140 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900141 lhs := ev.evalExpr(ast.lhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900142 ev.curRule.output = lhs
Shinichiro Hamajie57b5692015-03-30 23:16:47 +0900143 rhs := strings.TrimSpace(ev.evalExpr(ast.rhs))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900144 if rhs != "" {
Shinichiro Hamajie57b5692015-03-30 23:16:47 +0900145 re, err := regexp.Compile(`\s+`)
146 if err != nil {
147 panic(err)
148 }
149 ev.curRule.inputs = re.Split(rhs, -1)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900150 }
151 var cmds []string
152 for _, cmd := range ast.cmds {
153 cmds = append(cmds, ev.evalExpr(cmd))
154 }
155 Log("RULE: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900156 ev.curRule.cmds = cmds
157 ev.outRules = append(ev.outRules, ev.curRule)
158 ev.curRule = nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900159}
160
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900161func (ev *Evaluator) evalRawExpr(ast *RawExprAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900162 ev.filename = ast.filename
163 ev.lineno = ast.lineno
164
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900165 result := ev.evalExpr(ast.expr)
166 if result != "" {
Shinichiro Hamaji91b105c2015-03-30 18:39:05 +0900167 // TODO: Fix rule_in_var.mk.
Shinichiro Hamaji0ec07702015-03-31 00:50:32 +0900168 Error(ast.filename, ast.lineno, "*** missing separator.")
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900169 }
170}
171
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900172func (ev *Evaluator) getVar(name string) (string, bool) {
173 value, present := ev.outVars[name]
174 if present {
175 return value, true
176 }
177 value, present = ev.vars[name]
178 if present {
179 return value, true
180 }
181 return "", false
182}
183
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900184func (ev *Evaluator) getVars() map[string]string {
185 vars := make(map[string]string)
186 for k, v := range ev.vars {
187 vars[k] = v
188 }
189 for k, v := range ev.outVars {
190 vars[k] = v
191 }
192 return vars
193}
194
195func (ev *Evaluator) evalInclude(ast *IncludeAST) {
196 ev.filename = ast.filename
197 ev.lineno = ast.lineno
198
199 // TODO: Handle glob
200 files := strings.Split(ev.evalExpr(ast.expr), " ")
201 for _, file := range files {
202 mk, err := ParseMakefile(file)
203 if err != nil {
204 if ast.op == "include" {
205 panic(err)
206 } else {
207 continue
208 }
209 }
210
211 er, err2 := Eval(mk, ev.getVars())
212 if err2 != nil {
213 panic(err2)
214 }
215
216 for k, v := range er.vars {
217 ev.outVars[k] = v
218 }
219 for _, r := range er.rules {
220 ev.outRules = append(ev.outRules, r)
221 }
222 for r, _ := range er.refs {
223 ev.refs[r] = true
224 }
225 }
226}
227
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900228func (ev *Evaluator) evalIf(ast *IfAST) {
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900229 var isTrue bool
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900230 switch ast.op {
231 case "ifdef", "ifndef":
232 value, _ := ev.getVar(ev.evalExpr(ast.lhs))
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900233 isTrue = (value != "") == (ast.op == "ifdef")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900234 case "ifeq", "ifneq":
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900235 lhs := ev.evalExpr(ast.lhs)
236 rhs := ev.evalExpr(ast.rhs)
237 isTrue = (lhs == rhs) == (ast.op == "ifeq")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900238 default:
239 panic(fmt.Sprintf("unknown if statement: %q", ast.op))
240 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900241
242 var stmts []AST
243 if isTrue {
244 stmts = ast.trueStmts
245 } else {
246 stmts = ast.falseStmts
247 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900248 for _, stmt := range stmts {
249 ev.eval(stmt)
250 }
251}
252
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900253func (ev *Evaluator) eval(ast AST) {
Fumitoshi Ukaie34c1792015-03-30 17:53:47 +0900254 ast.eval(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900255}
256
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900257func Eval(mk Makefile, vars map[string]string) (er *EvalResult, err error) {
258 ev := newEvaluator(vars)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900259 defer func() {
260 if r := recover(); r != nil {
261 err = fmt.Errorf("panic: %v", r)
262 }
263 }()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900264 for _, stmt := range mk.stmts {
265 ev.eval(stmt)
266 }
267 return &EvalResult{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900268 vars: ev.outVars,
269 rules: ev.outRules,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900270 refs: ev.refs,
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900271 }, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900272}