blob: acaf58880bca9686bbfb9a9ac15038e339967325 [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
9type Rule struct {
10 output string
11 inputs []string
12 cmds []string
13}
14
15type EvalResult struct {
16 vars map[string]string
17 rules []*Rule
18 refs map[string]bool
19}
20
21type Evaluator struct {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090022 outVars map[string]string
23 outRules []*Rule
24 refs map[string]bool
25 vars map[string]string
26 curRule *Rule
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090027
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090028 funcs map[string]Func
29
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090030 filename string
31 lineno int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090032}
33
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090034func newEvaluator(vars map[string]string) *Evaluator {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090035 return &Evaluator{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090036 outVars: make(map[string]string),
37 refs: make(map[string]bool),
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090038 vars: vars,
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090039 funcs: map[string]Func{
40 "wildcard": funcWildcard,
41 "shell": funcShell,
42 "warning": funcWarning,
43 },
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090044 }
45}
46
47func (ev *Evaluator) evalFunction(ex string) (string, bool) {
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090048 i := strings.IndexAny(ex, " \t")
49 if i < 0 {
50 return "", false
51 }
52 cmd := strings.TrimSpace(ex[:i])
53 args := strings.TrimLeft(ex[i+1:], " \t")
54 if f, ok := ev.funcs[cmd]; ok {
55 return f(ev, args), true
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090056 }
57 return "", false
58}
59
60func (ev *Evaluator) evalExprSlice(ex string, term byte) (string, int) {
61 var buf bytes.Buffer
62 i := 0
63 for i < len(ex) && ex[i] != term {
64 ch := ex[i]
65 i++
66 switch ch {
67 case '$':
68 if i >= len(ex) || ex[i] == term {
69 continue
70 }
71
72 var varname string
73 switch ex[i] {
74 case '@':
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090075 buf.WriteString(ev.curRule.output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090076 i++
77 continue
78 case '(':
79 v, j := ev.evalExprSlice(ex[i+1:], ')')
80 i += j + 2
81 if r, done := ev.evalFunction(v); done {
82 buf.WriteString(r)
83 continue
84 }
85
86 varname = v
87 default:
88 varname = string(ex[i])
89 i++
90 }
91
92 value, present := ev.vars[varname]
93 if !present {
94 ev.refs[varname] = true
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090095 value = ev.outVars[varname]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090096 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +090097 buf.WriteString(ev.evalExpr(value))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090098
99 default:
100 buf.WriteByte(ch)
101 }
102 }
103 return buf.String(), i
104}
105
106func (ev *Evaluator) evalExpr(ex string) string {
107 r, i := ev.evalExprSlice(ex, 0)
108 if len(ex) != i {
109 panic("Had a null character?")
110 }
111 return r
112}
113
114func (ev *Evaluator) evalAssign(ast *AssignAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900115 ev.filename = ast.filename
116 ev.lineno = ast.lineno
117
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900118 lhs := ev.evalExpr(ast.lhs)
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900119 rhs := ast.evalRHS(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900120 Log("ASSIGN: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900121 ev.outVars[lhs] = rhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900122}
123
124func (ev *Evaluator) evalRule(ast *RuleAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900125 ev.filename = ast.filename
126 ev.lineno = ast.lineno
127
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900128 ev.curRule = &Rule{}
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900129 lhs := ev.evalExpr(ast.lhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900130 ev.curRule.output = lhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900131 rhs := ev.evalExpr(ast.rhs)
132 if rhs != "" {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900133 ev.curRule.inputs = strings.Split(rhs, " ")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900134 }
135 var cmds []string
136 for _, cmd := range ast.cmds {
137 cmds = append(cmds, ev.evalExpr(cmd))
138 }
139 Log("RULE: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900140 ev.curRule.cmds = cmds
141 ev.outRules = append(ev.outRules, ev.curRule)
142 ev.curRule = nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900143}
144
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900145func (ev *Evaluator) evalRawExpr(ast *RawExprAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900146 ev.filename = ast.filename
147 ev.lineno = ast.lineno
148
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900149 result := ev.evalExpr(ast.expr)
150 if result != "" {
Shinichiro Hamaji91b105c2015-03-30 18:39:05 +0900151 // TODO: Fix rule_in_var.mk.
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900152 fmt.Printf("%s:%d: *** missing separator. Stop.\n", ast.filename, ast.lineno)
153 }
154}
155
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900156func (ev *Evaluator) getVars() map[string]string {
157 vars := make(map[string]string)
158 for k, v := range ev.vars {
159 vars[k] = v
160 }
161 for k, v := range ev.outVars {
162 vars[k] = v
163 }
164 return vars
165}
166
167func (ev *Evaluator) evalInclude(ast *IncludeAST) {
168 ev.filename = ast.filename
169 ev.lineno = ast.lineno
170
171 // TODO: Handle glob
172 files := strings.Split(ev.evalExpr(ast.expr), " ")
173 for _, file := range files {
174 mk, err := ParseMakefile(file)
175 if err != nil {
176 if ast.op == "include" {
177 panic(err)
178 } else {
179 continue
180 }
181 }
182
183 er, err2 := Eval(mk, ev.getVars())
184 if err2 != nil {
185 panic(err2)
186 }
187
188 for k, v := range er.vars {
189 ev.outVars[k] = v
190 }
191 for _, r := range er.rules {
192 ev.outRules = append(ev.outRules, r)
193 }
194 for r, _ := range er.refs {
195 ev.refs[r] = true
196 }
197 }
198}
199
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900200func (ev *Evaluator) eval(ast AST) {
Fumitoshi Ukaie34c1792015-03-30 17:53:47 +0900201 ast.eval(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900202}
203
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900204func Eval(mk Makefile, vars map[string]string) (er *EvalResult, err error) {
205 ev := newEvaluator(vars)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900206 defer func() {
207 if r := recover(); r != nil {
208 err = fmt.Errorf("panic: %v", r)
209 }
210 }()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900211 for _, stmt := range mk.stmts {
212 ev.eval(stmt)
213 }
214 return &EvalResult{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900215 vars: ev.outVars,
216 rules: ev.outRules,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900217 refs: ev.refs,
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900218 }, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900219}