blob: 75009a8b52de02772b263c36ef7e8ac2a89a95dd [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,
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090035 "wildcard": funcWildcard,
36 "shell": funcShell,
37 "warning": funcWarning,
38 },
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090039 }
40}
41
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090042func (ev *Evaluator) evalFunction(args []string) (string, bool) {
43 if len(args) == 0 {
44 return "", false
45 }
46 i := strings.IndexAny(args[0], " \t")
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090047 if i < 0 {
48 return "", false
49 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090050 cmd := strings.TrimSpace(args[0][:i])
51 args[0] = strings.TrimLeft(args[0][i+1:], " \t")
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090052 if f, ok := ev.funcs[cmd]; ok {
53 return f(ev, args), true
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090054 }
55 return "", false
56}
57
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090058func (ev *Evaluator) evalExprSlice(ex string) (string, int) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090059 var buf bytes.Buffer
60 i := 0
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090061Loop:
62 for i < len(ex) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090063 ch := ex[i]
64 i++
65 switch ch {
66 case '$':
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090067 if i >= len(ex) {
68 break Loop
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090069 }
70
71 var varname string
72 switch ex[i] {
Shinichiro Hamaji894bb822015-04-01 00:54:46 +090073 case '@', '$':
74 buf.WriteByte('$')
75 buf.WriteByte(ex[i])
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090076 i++
77 continue
Fumitoshi Ukaiad720602015-03-31 10:29:59 +090078 case '(', '{':
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090079 args, rest, err := parseExpr(ex[i:])
80 if err != nil {
Fumitoshi Ukaiad720602015-03-31 10:29:59 +090081 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090082 i += rest
83 if r, done := ev.evalFunction(args); done {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090084 buf.WriteString(r)
85 continue
86 }
87
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090088 varname = strings.Join(args, ",")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090089 default:
90 varname = string(ex[i])
91 i++
92 }
93
94 value, present := ev.vars[varname]
95 if !present {
96 ev.refs[varname] = true
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090097 value = ev.outVars[varname]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090098 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +090099 buf.WriteString(ev.evalExpr(value))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900100
101 default:
102 buf.WriteByte(ch)
103 }
104 }
105 return buf.String(), i
106}
107
Shinichiro Hamaji894bb822015-04-01 00:54:46 +0900108func (ev *Evaluator) evalExprCommand(ex string) string {
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900109 r, i := ev.evalExprSlice(ex)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900110 if len(ex) != i {
Fumitoshi Ukaiad720602015-03-31 10:29:59 +0900111 panic(fmt.Sprintf("Had a null character? %q, %d", ex, i))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900112 }
113 return r
114}
115
Shinichiro Hamaji894bb822015-04-01 00:54:46 +0900116func expandCommandVars(cmd string, output string) string {
117 // Fast path.
118 if strings.IndexByte(cmd, '$') < 0 {
119 return cmd
120 }
121
122 var buf bytes.Buffer
123 i := 0
124 for i < len(cmd) {
125 ch := cmd[i]
126 i++
127 if ch != '$' || i >= len(cmd) {
128 buf.WriteByte(ch)
129 continue
130 }
131 switch cmd[i] {
132 case '@':
133 buf.WriteString(output)
134 case '$':
135 buf.WriteByte('$')
136 default:
137 panic(fmt.Sprintf("TODO: not implemented yet: $%c", cmd[i]))
138 }
139 i++
140 }
141 return buf.String()
142}
143
144func (ev *Evaluator) evalExpr(ex string) string {
145 ex = ev.evalExprCommand(ex)
146 return expandCommandVars(ex, "")
147}
148
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900149func (ev *Evaluator) evalAssign(ast *AssignAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900150 ev.filename = ast.filename
151 ev.lineno = ast.lineno
152
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900153 lhs := ev.evalExpr(ast.lhs)
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900154 rhs := ast.evalRHS(ev, lhs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900155 Log("ASSIGN: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900156 ev.outVars[lhs] = rhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900157}
158
Shinichiro Hamajide829712015-03-31 18:26:56 +0900159func (ev *Evaluator) evalMaybeRule(ast *MaybeRuleAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900160 ev.filename = ast.filename
161 ev.lineno = ast.lineno
162
Shinichiro Hamajide829712015-03-31 18:26:56 +0900163 line := ev.evalExpr(ast.expr)
Shinichiro Hamaji04932612015-03-31 23:46:56 +0900164
Shinichiro Hamajide829712015-03-31 18:26:56 +0900165 if strings.TrimSpace(line) == "" {
166 if len(ast.cmds) > 0 {
167 Error(ast.filename, ast.cmdLineno, "*** commands commence before first target.")
168 }
169 return
170 }
171
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900172 ev.curRule = &Rule{
Fumitoshi Ukaiad720602015-03-31 10:29:59 +0900173 filename: ast.filename,
174 lineno: ast.lineno,
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900175 cmdLineno: ast.cmdLineno,
176 }
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +0900177 if err := ev.curRule.parse(line); err != "" {
178 Error(ast.filename, ast.lineno, err)
179 }
Shinichiro Hamajib2fd38d2015-04-01 01:12:19 +0900180 // It seems rules with no outputs are siliently ignored.
181 if len(ev.curRule.outputs) == 0 {
182 ev.curRule = nil
183 return
184 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900185
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900186 var cmds []string
187 for _, cmd := range ast.cmds {
Shinichiro Hamaji894bb822015-04-01 00:54:46 +0900188 cmds = append(cmds, ev.evalExprCommand(cmd))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900189 }
Shinichiro Hamaji04932612015-03-31 23:46:56 +0900190
191 // TODO: Pretty print.
192 //Log("RULE: %s=%s (%d commands)", lhs, rhs, len(cmds))
193
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900194 ev.curRule.cmds = cmds
195 ev.outRules = append(ev.outRules, ev.curRule)
196 ev.curRule = nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900197}
198
Shinichiro Hamajide829712015-03-31 18:26:56 +0900199/*
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900200func (ev *Evaluator) evalRawExpr(ast *RawExprAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900201 ev.filename = ast.filename
202 ev.lineno = ast.lineno
203
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900204 result := ev.evalExpr(ast.expr)
205 if result != "" {
Shinichiro Hamaji91b105c2015-03-30 18:39:05 +0900206 // TODO: Fix rule_in_var.mk.
Shinichiro Hamaji0ec07702015-03-31 00:50:32 +0900207 Error(ast.filename, ast.lineno, "*** missing separator.")
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900208 }
209}
Shinichiro Hamajide829712015-03-31 18:26:56 +0900210*/
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900211
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900212func (ev *Evaluator) getVar(name string) (string, bool) {
213 value, present := ev.outVars[name]
214 if present {
215 return value, true
216 }
217 value, present = ev.vars[name]
218 if present {
219 return value, true
220 }
221 return "", false
222}
223
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900224func (ev *Evaluator) getVars() map[string]string {
225 vars := make(map[string]string)
226 for k, v := range ev.vars {
227 vars[k] = v
228 }
229 for k, v := range ev.outVars {
230 vars[k] = v
231 }
232 return vars
233}
234
235func (ev *Evaluator) evalInclude(ast *IncludeAST) {
236 ev.filename = ast.filename
237 ev.lineno = ast.lineno
238
239 // TODO: Handle glob
240 files := strings.Split(ev.evalExpr(ast.expr), " ")
241 for _, file := range files {
242 mk, err := ParseMakefile(file)
243 if err != nil {
244 if ast.op == "include" {
245 panic(err)
246 } else {
247 continue
248 }
249 }
250
251 er, err2 := Eval(mk, ev.getVars())
252 if err2 != nil {
253 panic(err2)
254 }
255
256 for k, v := range er.vars {
257 ev.outVars[k] = v
258 }
259 for _, r := range er.rules {
260 ev.outRules = append(ev.outRules, r)
261 }
262 for r, _ := range er.refs {
263 ev.refs[r] = true
264 }
265 }
266}
267
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900268func (ev *Evaluator) evalIf(ast *IfAST) {
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900269 var isTrue bool
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900270 switch ast.op {
271 case "ifdef", "ifndef":
272 value, _ := ev.getVar(ev.evalExpr(ast.lhs))
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900273 isTrue = (value != "") == (ast.op == "ifdef")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900274 case "ifeq", "ifneq":
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900275 lhs := ev.evalExpr(ast.lhs)
276 rhs := ev.evalExpr(ast.rhs)
277 isTrue = (lhs == rhs) == (ast.op == "ifeq")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900278 default:
279 panic(fmt.Sprintf("unknown if statement: %q", ast.op))
280 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900281
282 var stmts []AST
283 if isTrue {
284 stmts = ast.trueStmts
285 } else {
286 stmts = ast.falseStmts
287 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900288 for _, stmt := range stmts {
289 ev.eval(stmt)
290 }
291}
292
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900293func (ev *Evaluator) eval(ast AST) {
Fumitoshi Ukaie34c1792015-03-30 17:53:47 +0900294 ast.eval(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900295}
296
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900297func Eval(mk Makefile, vars map[string]string) (er *EvalResult, err error) {
298 ev := newEvaluator(vars)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900299 defer func() {
300 if r := recover(); r != nil {
301 err = fmt.Errorf("panic: %v", r)
302 }
303 }()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900304 for _, stmt := range mk.stmts {
305 ev.eval(stmt)
306 }
307 return &EvalResult{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900308 vars: ev.outVars,
309 rules: ev.outRules,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900310 refs: ev.refs,
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900311 }, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900312}