blob: 506ffd5f82800b0ad9094c6d670a6d334406eded [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"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09006 "strings"
7)
8
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09009type EvalResult struct {
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +090010 vars Vars
11 rules []*Rule
12 ruleVars map[string]Vars
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090013}
14
15type Evaluator struct {
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +090016 paramVars []tmpval // $1 => paramVars[1]
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +090017 outVars Vars
18 outRules []*Rule
19 outRuleVars map[string]Vars
20 vars Vars
21 lastRule *Rule
22 currentScope Vars
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090023
24 filename string
25 lineno int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090026}
27
Shinichiro Hamajicc919ae2015-04-09 17:23:30 +090028func newEvaluator(vars map[string]Var) *Evaluator {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090029 return &Evaluator{
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +090030 outVars: make(Vars),
31 vars: vars,
32 outRuleVars: make(map[string]Vars),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090033 }
34}
35
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090036func (ev *Evaluator) Value(v Value) []byte {
Fumitoshi Ukai6ac7f692015-04-15 17:13:51 +090037 if v, ok := v.(Valuer); ok {
38 return v.Value()
39 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090040 var buf bytes.Buffer
41 v.Eval(&buf, ev)
42 return buf.Bytes()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090043}
44
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090045// TODO(ukai): use unicode.IsSpace?
46func isWhitespace(b byte) bool {
47 switch b {
48 case ' ', '\t', '\n', '\r':
49 return true
Shinichiro Hamajifce5a452015-04-09 17:02:23 +090050 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090051 return false
52}
Shinichiro Hamajifce5a452015-04-09 17:02:23 +090053
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090054func (ev *Evaluator) Values(v Value) [][]byte {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090055 var buf bytes.Buffer
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090056 v.Eval(&buf, ev)
57 val := buf.Bytes()
58 var values [][]byte
59 b := -1
60 for i := 0; i < len(val); i++ {
61 if b < 0 {
62 if isWhitespace(val[i]) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090063 continue
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090064 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090065 b = i
66 } else {
67 if isWhitespace(val[i]) {
68 values = append(values, val[b:i])
69 b = -1
70 continue
Fumitoshi Ukai0822c412015-04-05 22:51:18 +090071 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090072 }
73 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090074 if b >= 0 {
75 values = append(values, val[b:])
76 }
77 return values
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090078}
79
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090080func (ev *Evaluator) evalAssign(ast *AssignAST) {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +090081 ev.lastRule = nil
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +090082 lhs, rhs := ev.evalAssignAST(ast)
83 Log("ASSIGN: %s=%q (flavor:%q)", lhs, rhs, rhs.Flavor())
Shinichiro Hamaji46ee5cf2015-04-06 18:07:10 +090084 if len(lhs) == 0 {
85 Error(ast.filename, ast.lineno, "*** empty variable name.")
86 }
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +090087 ev.outVars.Assign(lhs, rhs)
88}
89
90func (ev *Evaluator) evalAssignAST(ast *AssignAST) (string, Var) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090091 ev.filename = ast.filename
92 ev.lineno = ast.lineno
93
Fumitoshi Ukai00178d12015-04-18 00:11:05 +090094 v, _, err := parseExpr([]byte(ast.lhs), nil)
95 if err != nil {
96 panic(fmt.Errorf("parse %s:%d %v", ev.filename, ev.lineno, err))
97 }
98 var lhs string
99 switch v := v.(type) {
100 case literal:
101 lhs = string(v)
102 case tmpval:
103 lhs = string(v)
104 default:
105 lhs = string(bytes.TrimSpace(ev.Value(v)))
106 }
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900107 rhs := ast.evalRHS(ev, lhs)
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900108 return lhs, rhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900109}
110
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +0900111func (ev *Evaluator) setTargetSpecificVar(assign *AssignAST, output string) {
112 vars, present := ev.outRuleVars[output]
113 if !present {
114 vars = make(Vars)
115 ev.outRuleVars[output] = vars
116 }
117 ev.currentScope = vars
118 lhs, rhs := ev.evalAssignAST(assign)
119 Log("rule outputs:%q assign:%q=%q (flavor:%q)", output, lhs, rhs, rhs.Flavor())
120 vars.Assign(lhs, TargetSpecificVar{v: rhs, op: assign.op})
121 ev.currentScope = nil
122}
123
Shinichiro Hamajide829712015-03-31 18:26:56 +0900124func (ev *Evaluator) evalMaybeRule(ast *MaybeRuleAST) {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900125 ev.lastRule = nil
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900126 ev.filename = ast.filename
127 ev.lineno = ast.lineno
128
Shinichiro Hamaji486e9de2015-04-09 15:20:32 +0900129 expr := ast.expr
130 if ast.semicolonIndex >= 0 {
131 expr = expr[0:ast.semicolonIndex]
132 }
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900133 if ast.equalIndex >= 0 {
134 expr = expr[0:ast.equalIndex]
135 }
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900136 lexpr, _, err := parseExpr([]byte(expr), nil)
137 if err != nil {
138 panic(fmt.Errorf("parse %s:%d %v", ev.filename, ev.lineno, err))
139 }
140 line := ev.Value(lexpr)
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900141 if ast.equalIndex >= 0 {
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900142 line = append(line, []byte(ast.expr[ast.equalIndex:])...)
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900143 }
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +0900144 Log("rule? %q=>%q", ast.expr, line)
Shinichiro Hamaji04932612015-03-31 23:46:56 +0900145
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900146 // See semicolon.mk.
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900147 if len(bytes.TrimRight(line, " \t\n;")) == 0 {
Shinichiro Hamajide829712015-03-31 18:26:56 +0900148 return
149 }
150
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900151 rule := &Rule{
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900152 filename: ast.filename,
153 lineno: ast.lineno,
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900154 }
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900155 assign, err := rule.parse(string(line)) // use []byte?
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900156 if err != nil {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900157 Error(ast.filename, ast.lineno, "%v", err.Error())
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +0900158 }
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900159 Log("rule %q => outputs:%q, inputs:%q", line, rule.outputs, rule.inputs)
Shinichiro Hamajide829712015-03-31 18:26:56 +0900160
Shinichiro Hamaji04932612015-03-31 23:46:56 +0900161 // TODO: Pretty print.
162 //Log("RULE: %s=%s (%d commands)", lhs, rhs, len(cmds))
163
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900164 if assign != nil {
Shinichiro Hamaji486e9de2015-04-09 15:20:32 +0900165 if ast.semicolonIndex >= 0 {
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900166 // TODO(ukai): reuse lexpr above?
167 lexpr, _, err := parseExpr([]byte(ast.expr), nil)
168 if err != nil {
169 panic(fmt.Errorf("parse %s:%d %v", ev.filename, ev.lineno, err))
170 }
171 assign, err = rule.parse(string(ev.Value(lexpr)))
Shinichiro Hamaji486e9de2015-04-09 15:20:32 +0900172 if err != nil {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900173 Error(ast.filename, ast.lineno, "%v", err.Error())
Shinichiro Hamaji486e9de2015-04-09 15:20:32 +0900174 }
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900175 }
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +0900176 for _, output := range rule.outputs {
177 ev.setTargetSpecificVar(assign, output)
Shinichiro Hamaji6cc5c612015-04-15 12:59:40 +0900178 }
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +0900179 for _, output := range rule.outputPatterns {
Fumitoshi Ukai935de962015-04-28 17:08:20 +0900180 ev.setTargetSpecificVar(assign, output.String())
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900181 }
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +0900182 return
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900183 }
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +0900184
185 if ast.semicolonIndex > 0 {
186 rule.cmds = append(rule.cmds, ast.expr[ast.semicolonIndex+1:])
187 }
188 Log("rule outputs:%q cmds:%q", rule.outputs, rule.cmds)
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900189 ev.lastRule = rule
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900190 ev.outRules = append(ev.outRules, rule)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900191}
192
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900193func (ev *Evaluator) evalCommand(ast *CommandAST) {
194 ev.filename = ast.filename
195 ev.lineno = ast.lineno
196 if ev.lastRule == nil {
Shinichiro Hamajib0e81162015-04-09 07:50:06 +0900197 // This could still be an assignment statement. See
198 // assign_after_tab.mk.
199 if strings.IndexByte(ast.cmd, '=') >= 0 {
Shinichiro Hamajic88618f2015-04-11 19:58:06 +0900200 line := trimLeftSpace(ast.cmd)
Shinichiro Hamajib0e81162015-04-09 07:50:06 +0900201 mk, err := ParseMakefileString(line, ast.filename, ast.lineno)
202 if err != nil {
203 panic(err)
204 }
205 if len(mk.stmts) == 1 && mk.stmts[0].(*AssignAST) != nil {
206 ev.eval(mk.stmts[0])
207 }
208 return
209 }
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900210 Error(ast.filename, ast.lineno, "*** commands commence before first target.")
211 }
212 ev.lastRule.cmds = append(ev.lastRule.cmds, ast.cmd)
213 if ev.lastRule.cmdLineno == 0 {
214 ev.lastRule.cmdLineno = ast.lineno
215 }
216}
217
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900218func (ev *Evaluator) LookupVar(name string) Var {
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +0900219 if ev.currentScope != nil {
220 v := ev.currentScope.Lookup(name)
221 if v.IsDefined() {
222 return v
223 }
224 }
225 v := ev.outVars.Lookup(name)
226 if v.IsDefined() {
227 return v
228 }
229 return ev.vars.Lookup(name)
230}
231
232func (ev *Evaluator) LookupVarInCurrentScope(name string) Var {
233 if ev.currentScope != nil {
234 v := ev.currentScope.Lookup(name)
235 return v
236 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900237 v := ev.outVars.Lookup(name)
238 if v.IsDefined() {
239 return v
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900240 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900241 return ev.vars.Lookup(name)
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900242}
243
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900244func (ev *Evaluator) evalInclude(ast *IncludeAST) {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900245 ev.lastRule = nil
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900246 ev.filename = ast.filename
247 ev.lineno = ast.lineno
248
Fumitoshi Ukaia9e51362015-04-17 10:26:00 +0900249 Log("%s:%d include %q", ev.filename, ev.lineno, ast.expr)
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900250 // TODO: Handle glob
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900251 v, _, err := parseExpr([]byte(ast.expr), nil)
252 if err != nil {
253 panic(err)
254 }
255 files := ev.Values(v)
256 for _, f := range files {
257 file := string(f)
Fumitoshi Ukaia9e51362015-04-17 10:26:00 +0900258 Log("Reading makefile %q", file)
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900259 mk, err := ParseMakefile(file)
260 if err != nil {
261 if ast.op == "include" {
262 panic(err)
263 } else {
264 continue
265 }
266 }
267
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900268 makefileList := ev.outVars.Lookup("MAKEFILE_LIST")
269 makefileList = makefileList.Append(ev, mk.filename)
270 ev.outVars.Assign("MAKEFILE_LIST", makefileList)
Shinichiro Hamajib2388ec2015-04-09 16:58:33 +0900271
272 for _, stmt := range mk.stmts {
273 ev.eval(stmt)
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900274 }
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900275 }
276}
277
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900278func (ev *Evaluator) evalIf(ast *IfAST) {
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900279 var isTrue bool
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900280 switch ast.op {
281 case "ifdef", "ifndef":
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900282 expr, _, err := parseExpr([]byte(ast.lhs), nil)
283 if err != nil {
284 panic(fmt.Errorf("ifdef parse %s:%d %v", ast.filename, ast.lineno, err))
285 }
286 vname := ev.Value(expr)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900287 v := ev.LookupVar(string(vname))
288 value := ev.Value(v)
289 isTrue = (len(value) > 0) == (ast.op == "ifdef")
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900290 Log("%s lhs=%q value=%q => %t", ast.op, ast.lhs, value, isTrue)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900291 case "ifeq", "ifneq":
Fumitoshi Ukai00178d12015-04-18 00:11:05 +0900292 lexpr, _, err := parseExpr([]byte(ast.lhs), nil)
293 if err != nil {
294 panic(fmt.Errorf("ifeq lhs parse %s:%d %v", ast.filename, ast.lineno, err))
295 }
296 rexpr, _, err := parseExpr([]byte(ast.rhs), nil)
297 if err != nil {
298 panic(fmt.Errorf("ifeq rhs parse %s:%d %v", ast.filename, ast.lineno, err))
299 }
300 lhs := string(ev.Value(lexpr))
301 rhs := string(ev.Value(rexpr))
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900302 isTrue = (lhs == rhs) == (ast.op == "ifeq")
Fumitoshi Ukai70084832015-04-05 23:27:28 +0900303 Log("%s lhs=%q %q rhs=%q %q => %t", ast.op, ast.lhs, lhs, ast.rhs, rhs, isTrue)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900304 default:
305 panic(fmt.Sprintf("unknown if statement: %q", ast.op))
306 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900307
308 var stmts []AST
309 if isTrue {
310 stmts = ast.trueStmts
311 } else {
312 stmts = ast.falseStmts
313 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900314 for _, stmt := range stmts {
315 ev.eval(stmt)
316 }
317}
318
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900319func (ev *Evaluator) eval(ast AST) {
Fumitoshi Ukaie34c1792015-03-30 17:53:47 +0900320 ast.eval(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900321}
322
Shinichiro Hamajicc919ae2015-04-09 17:23:30 +0900323func Eval(mk Makefile, vars Vars) (er *EvalResult, err error) {
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900324 ev := newEvaluator(vars)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900325 defer func() {
326 if r := recover(); r != nil {
Fumitoshi Ukaia9e51362015-04-17 10:26:00 +0900327 err = fmt.Errorf("panic in eval %s: %v", mk.filename, r)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900328 }
329 }()
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900330
331 makefile_list := vars.Lookup("MAKEFILE_LIST")
332 makefile_list = makefile_list.Append(ev, mk.filename)
333 ev.outVars.Assign("MAKEFILE_LIST", makefile_list)
334
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900335 for _, stmt := range mk.stmts {
336 ev.eval(stmt)
337 }
338 return &EvalResult{
Shinichiro Hamajia485d2f2015-04-16 14:03:24 +0900339 vars: ev.outVars,
340 rules: ev.outRules,
341 ruleVars: ev.outRuleVars,
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900342 }, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900343}