blob: e3b90aef14d025636f249f05a16fc549fd0342b4 [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 {
10 vars map[string]string
11 rules []*Rule
12 refs map[string]bool
13}
14
15type Evaluator struct {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090016 outVars map[string]string
17 outRules []*Rule
18 refs map[string]bool
19 vars map[string]string
20 curRule *Rule
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090021
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090022 funcs map[string]Func
23
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090024 filename string
25 lineno int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090026}
27
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090028func newEvaluator(vars map[string]string) *Evaluator {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090029 return &Evaluator{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090030 outVars: make(map[string]string),
31 refs: make(map[string]bool),
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090032 vars: vars,
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090033 funcs: map[string]Func{
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090034 "subst": funcSubst,
Shinichiro Hamajiea8b56d2015-04-01 03:39:29 +090035 "patsubst": funcPatsubst,
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090036 "wildcard": funcWildcard,
37 "shell": funcShell,
38 "warning": funcWarning,
39 },
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090040 }
41}
42
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090043func (ev *Evaluator) evalFunction(args []string) (string, bool) {
44 if len(args) == 0 {
45 return "", false
46 }
47 i := strings.IndexAny(args[0], " \t")
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090048 if i < 0 {
49 return "", false
50 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090051 cmd := strings.TrimSpace(args[0][:i])
52 args[0] = strings.TrimLeft(args[0][i+1:], " \t")
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090053 if f, ok := ev.funcs[cmd]; ok {
54 return f(ev, args), true
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090055 }
56 return "", false
57}
58
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090059func (ev *Evaluator) evalExprSlice(ex string) (string, int) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090060 var buf bytes.Buffer
61 i := 0
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090062Loop:
63 for i < len(ex) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090064 ch := ex[i]
65 i++
66 switch ch {
67 case '$':
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090068 if i >= len(ex) {
69 break Loop
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090070 }
71
72 var varname string
73 switch ex[i] {
Shinichiro Hamaji894bb822015-04-01 00:54:46 +090074 case '@', '$':
75 buf.WriteByte('$')
76 buf.WriteByte(ex[i])
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090077 i++
78 continue
Fumitoshi Ukaiad720602015-03-31 10:29:59 +090079 case '(', '{':
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090080 args, rest, err := parseExpr(ex[i:])
81 if err != nil {
Fumitoshi Ukaiad720602015-03-31 10:29:59 +090082 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090083 i += rest
84 if r, done := ev.evalFunction(args); done {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090085 buf.WriteString(r)
86 continue
87 }
88
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090089 varname = strings.Join(args, ",")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090090 default:
91 varname = string(ex[i])
92 i++
93 }
94
95 value, present := ev.vars[varname]
96 if !present {
97 ev.refs[varname] = true
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090098 value = ev.outVars[varname]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090099 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900100 buf.WriteString(ev.evalExpr(value))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900101
102 default:
103 buf.WriteByte(ch)
104 }
105 }
106 return buf.String(), i
107}
108
Shinichiro Hamaji894bb822015-04-01 00:54:46 +0900109func (ev *Evaluator) evalExprCommand(ex string) string {
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900110 r, i := ev.evalExprSlice(ex)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900111 if len(ex) != i {
Fumitoshi Ukaiad720602015-03-31 10:29:59 +0900112 panic(fmt.Sprintf("Had a null character? %q, %d", ex, i))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900113 }
114 return r
115}
116
Shinichiro Hamaji894bb822015-04-01 00:54:46 +0900117func expandCommandVars(cmd string, output string) string {
118 // Fast path.
119 if strings.IndexByte(cmd, '$') < 0 {
120 return cmd
121 }
122
123 var buf bytes.Buffer
124 i := 0
125 for i < len(cmd) {
126 ch := cmd[i]
127 i++
128 if ch != '$' || i >= len(cmd) {
129 buf.WriteByte(ch)
130 continue
131 }
132 switch cmd[i] {
133 case '@':
134 buf.WriteString(output)
135 case '$':
136 buf.WriteByte('$')
137 default:
138 panic(fmt.Sprintf("TODO: not implemented yet: $%c", cmd[i]))
139 }
140 i++
141 }
142 return buf.String()
143}
144
145func (ev *Evaluator) evalExpr(ex string) string {
146 ex = ev.evalExprCommand(ex)
147 return expandCommandVars(ex, "")
148}
149
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900150func (ev *Evaluator) evalAssign(ast *AssignAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900151 ev.filename = ast.filename
152 ev.lineno = ast.lineno
153
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900154 lhs := ev.evalExpr(ast.lhs)
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900155 rhs := ast.evalRHS(ev, lhs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900156 Log("ASSIGN: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900157 ev.outVars[lhs] = rhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900158}
159
Shinichiro Hamajide829712015-03-31 18:26:56 +0900160func (ev *Evaluator) evalMaybeRule(ast *MaybeRuleAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900161 ev.filename = ast.filename
162 ev.lineno = ast.lineno
163
Shinichiro Hamajide829712015-03-31 18:26:56 +0900164 line := ev.evalExpr(ast.expr)
Shinichiro Hamaji04932612015-03-31 23:46:56 +0900165
Shinichiro Hamajide829712015-03-31 18:26:56 +0900166 if strings.TrimSpace(line) == "" {
167 if len(ast.cmds) > 0 {
168 Error(ast.filename, ast.cmdLineno, "*** commands commence before first target.")
169 }
170 return
171 }
172
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900173 ev.curRule = &Rule{
Fumitoshi Ukaiad720602015-03-31 10:29:59 +0900174 filename: ast.filename,
175 lineno: ast.lineno,
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900176 cmdLineno: ast.cmdLineno,
177 }
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +0900178 if err := ev.curRule.parse(line); err != "" {
179 Error(ast.filename, ast.lineno, err)
180 }
Shinichiro Hamajib2fd38d2015-04-01 01:12:19 +0900181 // It seems rules with no outputs are siliently ignored.
182 if len(ev.curRule.outputs) == 0 {
183 ev.curRule = nil
184 return
185 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900186
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900187 var cmds []string
188 for _, cmd := range ast.cmds {
Shinichiro Hamaji894bb822015-04-01 00:54:46 +0900189 cmds = append(cmds, ev.evalExprCommand(cmd))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900190 }
Shinichiro Hamaji04932612015-03-31 23:46:56 +0900191
192 // TODO: Pretty print.
193 //Log("RULE: %s=%s (%d commands)", lhs, rhs, len(cmds))
194
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900195 ev.curRule.cmds = cmds
196 ev.outRules = append(ev.outRules, ev.curRule)
197 ev.curRule = nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900198}
199
Shinichiro Hamajide829712015-03-31 18:26:56 +0900200/*
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900201func (ev *Evaluator) evalRawExpr(ast *RawExprAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900202 ev.filename = ast.filename
203 ev.lineno = ast.lineno
204
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900205 result := ev.evalExpr(ast.expr)
206 if result != "" {
Shinichiro Hamaji91b105c2015-03-30 18:39:05 +0900207 // TODO: Fix rule_in_var.mk.
Shinichiro Hamaji0ec07702015-03-31 00:50:32 +0900208 Error(ast.filename, ast.lineno, "*** missing separator.")
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900209 }
210}
Shinichiro Hamajide829712015-03-31 18:26:56 +0900211*/
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900212
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900213func (ev *Evaluator) getVar(name string) (string, bool) {
214 value, present := ev.outVars[name]
215 if present {
216 return value, true
217 }
218 value, present = ev.vars[name]
219 if present {
220 return value, true
221 }
222 return "", false
223}
224
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900225func (ev *Evaluator) getVars() map[string]string {
226 vars := make(map[string]string)
227 for k, v := range ev.vars {
228 vars[k] = v
229 }
230 for k, v := range ev.outVars {
231 vars[k] = v
232 }
233 return vars
234}
235
236func (ev *Evaluator) evalInclude(ast *IncludeAST) {
237 ev.filename = ast.filename
238 ev.lineno = ast.lineno
239
240 // TODO: Handle glob
241 files := strings.Split(ev.evalExpr(ast.expr), " ")
242 for _, file := range files {
243 mk, err := ParseMakefile(file)
244 if err != nil {
245 if ast.op == "include" {
246 panic(err)
247 } else {
248 continue
249 }
250 }
251
252 er, err2 := Eval(mk, ev.getVars())
253 if err2 != nil {
254 panic(err2)
255 }
256
257 for k, v := range er.vars {
258 ev.outVars[k] = v
259 }
260 for _, r := range er.rules {
261 ev.outRules = append(ev.outRules, r)
262 }
263 for r, _ := range er.refs {
264 ev.refs[r] = true
265 }
266 }
267}
268
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900269func (ev *Evaluator) evalIf(ast *IfAST) {
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900270 var isTrue bool
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900271 switch ast.op {
272 case "ifdef", "ifndef":
273 value, _ := ev.getVar(ev.evalExpr(ast.lhs))
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900274 isTrue = (value != "") == (ast.op == "ifdef")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900275 case "ifeq", "ifneq":
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900276 lhs := ev.evalExpr(ast.lhs)
277 rhs := ev.evalExpr(ast.rhs)
278 isTrue = (lhs == rhs) == (ast.op == "ifeq")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900279 default:
280 panic(fmt.Sprintf("unknown if statement: %q", ast.op))
281 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900282
283 var stmts []AST
284 if isTrue {
285 stmts = ast.trueStmts
286 } else {
287 stmts = ast.falseStmts
288 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900289 for _, stmt := range stmts {
290 ev.eval(stmt)
291 }
292}
293
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900294func (ev *Evaluator) eval(ast AST) {
Fumitoshi Ukaie34c1792015-03-30 17:53:47 +0900295 ast.eval(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900296}
297
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900298func Eval(mk Makefile, vars map[string]string) (er *EvalResult, err error) {
299 ev := newEvaluator(vars)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900300 defer func() {
301 if r := recover(); r != nil {
302 err = fmt.Errorf("panic: %v", r)
303 }
304 }()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900305 for _, stmt := range mk.stmts {
306 ev.eval(stmt)
307 }
308 return &EvalResult{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900309 vars: ev.outVars,
310 rules: ev.outRules,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900311 refs: ev.refs,
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900312 }, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900313}