blob: 060763c9f6bbea3b03a22d06d3f21c92ea9ed5f9 [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{
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090044 "subst": funcSubst,
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090045 "wildcard": funcWildcard,
46 "shell": funcShell,
47 "warning": funcWarning,
48 },
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090049 }
50}
51
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090052func (ev *Evaluator) evalFunction(args []string) (string, bool) {
53 if len(args) == 0 {
54 return "", false
55 }
56 i := strings.IndexAny(args[0], " \t")
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090057 if i < 0 {
58 return "", false
59 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090060 cmd := strings.TrimSpace(args[0][:i])
61 args[0] = strings.TrimLeft(args[0][i+1:], " \t")
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090062 if f, ok := ev.funcs[cmd]; ok {
63 return f(ev, args), true
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090064 }
65 return "", false
66}
67
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090068func (ev *Evaluator) evalExprSlice(ex string) (string, int) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090069 var buf bytes.Buffer
70 i := 0
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090071Loop:
72 for i < len(ex) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090073 ch := ex[i]
74 i++
75 switch ch {
76 case '$':
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090077 if i >= len(ex) {
78 break Loop
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090079 }
80
81 var varname string
82 switch ex[i] {
83 case '@':
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090084 buf.WriteString(ev.curRule.output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090085 i++
86 continue
Fumitoshi Ukaiad720602015-03-31 10:29:59 +090087 case '(', '{':
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090088 args, rest, err := parseExpr(ex[i:])
89 if err != nil {
Fumitoshi Ukaiad720602015-03-31 10:29:59 +090090 }
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090091 i += rest
92 if r, done := ev.evalFunction(args); done {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090093 buf.WriteString(r)
94 continue
95 }
96
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090097 varname = strings.Join(args, ",")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090098 default:
99 varname = string(ex[i])
100 i++
101 }
102
103 value, present := ev.vars[varname]
104 if !present {
105 ev.refs[varname] = true
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900106 value = ev.outVars[varname]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900107 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900108 buf.WriteString(ev.evalExpr(value))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900109
110 default:
111 buf.WriteByte(ch)
112 }
113 }
114 return buf.String(), i
115}
116
117func (ev *Evaluator) evalExpr(ex string) string {
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900118 r, i := ev.evalExprSlice(ex)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900119 if len(ex) != i {
Fumitoshi Ukaiad720602015-03-31 10:29:59 +0900120 panic(fmt.Sprintf("Had a null character? %q, %d", ex, i))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900121 }
122 return r
123}
124
125func (ev *Evaluator) evalAssign(ast *AssignAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900126 ev.filename = ast.filename
127 ev.lineno = ast.lineno
128
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900129 lhs := ev.evalExpr(ast.lhs)
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900130 rhs := ast.evalRHS(ev, lhs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900131 Log("ASSIGN: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900132 ev.outVars[lhs] = rhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900133}
134
Shinichiro Hamajide829712015-03-31 18:26:56 +0900135func (ev *Evaluator) evalMaybeRule(ast *MaybeRuleAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900136 ev.filename = ast.filename
137 ev.lineno = ast.lineno
138
Shinichiro Hamajide829712015-03-31 18:26:56 +0900139 line := ev.evalExpr(ast.expr)
140 if strings.TrimSpace(line) == "" {
141 if len(ast.cmds) > 0 {
142 Error(ast.filename, ast.cmdLineno, "*** commands commence before first target.")
143 }
144 return
145 }
146
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900147 ev.curRule = &Rule{
Fumitoshi Ukaiad720602015-03-31 10:29:59 +0900148 filename: ast.filename,
149 lineno: ast.lineno,
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900150 cmdLineno: ast.cmdLineno,
151 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900152
153 colonIndex := strings.IndexByte(line, ':')
154 if colonIndex < 0 {
155 Error(ast.filename, ast.lineno, "*** missing separator.")
156 }
157
158 lhs := line[:colonIndex]
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900159 ev.curRule.output = lhs
Shinichiro Hamajide829712015-03-31 18:26:56 +0900160 rhs := strings.TrimSpace(line[colonIndex+1:])
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900161 if rhs != "" {
Shinichiro Hamajie57b5692015-03-30 23:16:47 +0900162 re, err := regexp.Compile(`\s+`)
163 if err != nil {
164 panic(err)
165 }
166 ev.curRule.inputs = re.Split(rhs, -1)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900167 }
168 var cmds []string
169 for _, cmd := range ast.cmds {
170 cmds = append(cmds, ev.evalExpr(cmd))
171 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900172 Log("RULE: %s=%s (%d commands)", lhs, rhs, len(cmds))
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900173 ev.curRule.cmds = cmds
174 ev.outRules = append(ev.outRules, ev.curRule)
175 ev.curRule = nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900176}
177
Shinichiro Hamajide829712015-03-31 18:26:56 +0900178/*
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900179func (ev *Evaluator) evalRawExpr(ast *RawExprAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900180 ev.filename = ast.filename
181 ev.lineno = ast.lineno
182
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900183 result := ev.evalExpr(ast.expr)
184 if result != "" {
Shinichiro Hamaji91b105c2015-03-30 18:39:05 +0900185 // TODO: Fix rule_in_var.mk.
Shinichiro Hamaji0ec07702015-03-31 00:50:32 +0900186 Error(ast.filename, ast.lineno, "*** missing separator.")
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900187 }
188}
Shinichiro Hamajide829712015-03-31 18:26:56 +0900189*/
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900190
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900191func (ev *Evaluator) getVar(name string) (string, bool) {
192 value, present := ev.outVars[name]
193 if present {
194 return value, true
195 }
196 value, present = ev.vars[name]
197 if present {
198 return value, true
199 }
200 return "", false
201}
202
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900203func (ev *Evaluator) getVars() map[string]string {
204 vars := make(map[string]string)
205 for k, v := range ev.vars {
206 vars[k] = v
207 }
208 for k, v := range ev.outVars {
209 vars[k] = v
210 }
211 return vars
212}
213
214func (ev *Evaluator) evalInclude(ast *IncludeAST) {
215 ev.filename = ast.filename
216 ev.lineno = ast.lineno
217
218 // TODO: Handle glob
219 files := strings.Split(ev.evalExpr(ast.expr), " ")
220 for _, file := range files {
221 mk, err := ParseMakefile(file)
222 if err != nil {
223 if ast.op == "include" {
224 panic(err)
225 } else {
226 continue
227 }
228 }
229
230 er, err2 := Eval(mk, ev.getVars())
231 if err2 != nil {
232 panic(err2)
233 }
234
235 for k, v := range er.vars {
236 ev.outVars[k] = v
237 }
238 for _, r := range er.rules {
239 ev.outRules = append(ev.outRules, r)
240 }
241 for r, _ := range er.refs {
242 ev.refs[r] = true
243 }
244 }
245}
246
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900247func (ev *Evaluator) evalIf(ast *IfAST) {
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900248 var isTrue bool
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900249 switch ast.op {
250 case "ifdef", "ifndef":
251 value, _ := ev.getVar(ev.evalExpr(ast.lhs))
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900252 isTrue = (value != "") == (ast.op == "ifdef")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900253 case "ifeq", "ifneq":
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900254 lhs := ev.evalExpr(ast.lhs)
255 rhs := ev.evalExpr(ast.rhs)
256 isTrue = (lhs == rhs) == (ast.op == "ifeq")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900257 default:
258 panic(fmt.Sprintf("unknown if statement: %q", ast.op))
259 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900260
261 var stmts []AST
262 if isTrue {
263 stmts = ast.trueStmts
264 } else {
265 stmts = ast.falseStmts
266 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900267 for _, stmt := range stmts {
268 ev.eval(stmt)
269 }
270}
271
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900272func (ev *Evaluator) eval(ast AST) {
Fumitoshi Ukaie34c1792015-03-30 17:53:47 +0900273 ast.eval(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900274}
275
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900276func Eval(mk Makefile, vars map[string]string) (er *EvalResult, err error) {
277 ev := newEvaluator(vars)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900278 defer func() {
279 if r := recover(); r != nil {
280 err = fmt.Errorf("panic: %v", r)
281 }
282 }()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900283 for _, stmt := range mk.stmts {
284 ev.eval(stmt)
285 }
286 return &EvalResult{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900287 vars: ev.outVars,
288 rules: ev.outRules,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900289 refs: ev.refs,
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900290 }, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900291}