blob: 23b4a83449efd36c0ded4b8aedff466d829b78ad [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
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +090013 filename string
14 lineno int
15 cmdLineno int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090016}
17
18type EvalResult struct {
19 vars map[string]string
20 rules []*Rule
21 refs map[string]bool
22}
23
24type Evaluator struct {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090025 outVars map[string]string
26 outRules []*Rule
27 refs map[string]bool
28 vars map[string]string
29 curRule *Rule
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090030
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090031 funcs map[string]Func
32
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090033 filename string
34 lineno int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090035}
36
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090037func newEvaluator(vars map[string]string) *Evaluator {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090038 return &Evaluator{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090039 outVars: make(map[string]string),
40 refs: make(map[string]bool),
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090041 vars: vars,
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090042 funcs: map[string]Func{
43 "wildcard": funcWildcard,
44 "shell": funcShell,
45 "warning": funcWarning,
46 },
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090047 }
48}
49
50func (ev *Evaluator) evalFunction(ex string) (string, bool) {
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090051 i := strings.IndexAny(ex, " \t")
52 if i < 0 {
53 return "", false
54 }
55 cmd := strings.TrimSpace(ex[:i])
56 args := strings.TrimLeft(ex[i+1:], " \t")
57 if f, ok := ev.funcs[cmd]; ok {
58 return f(ev, args), true
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090059 }
60 return "", false
61}
62
63func (ev *Evaluator) evalExprSlice(ex string, term byte) (string, int) {
64 var buf bytes.Buffer
65 i := 0
66 for i < len(ex) && ex[i] != term {
67 ch := ex[i]
68 i++
69 switch ch {
70 case '$':
71 if i >= len(ex) || ex[i] == term {
72 continue
73 }
74
75 var varname string
76 switch ex[i] {
77 case '@':
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090078 buf.WriteString(ev.curRule.output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090079 i++
80 continue
81 case '(':
82 v, j := ev.evalExprSlice(ex[i+1:], ')')
83 i += j + 2
84 if r, done := ev.evalFunction(v); done {
85 buf.WriteString(r)
86 continue
87 }
88
89 varname = v
90 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
109func (ev *Evaluator) evalExpr(ex string) string {
110 r, i := ev.evalExprSlice(ex, 0)
111 if len(ex) != i {
112 panic("Had a null character?")
113 }
114 return r
115}
116
117func (ev *Evaluator) evalAssign(ast *AssignAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900118 ev.filename = ast.filename
119 ev.lineno = ast.lineno
120
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900121 lhs := ev.evalExpr(ast.lhs)
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900122 rhs := ast.evalRHS(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900123 Log("ASSIGN: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900124 ev.outVars[lhs] = rhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900125}
126
127func (ev *Evaluator) evalRule(ast *RuleAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900128 ev.filename = ast.filename
129 ev.lineno = ast.lineno
130
Shinichiro Hamaji7c4e3252015-03-30 23:04:25 +0900131 ev.curRule = &Rule{
132 filename: ast.filename,
133 lineno: ast.lineno,
134 cmdLineno: ast.cmdLineno,
135 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900136 lhs := ev.evalExpr(ast.lhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900137 ev.curRule.output = lhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900138 rhs := ev.evalExpr(ast.rhs)
139 if rhs != "" {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900140 ev.curRule.inputs = strings.Split(rhs, " ")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900141 }
142 var cmds []string
143 for _, cmd := range ast.cmds {
144 cmds = append(cmds, ev.evalExpr(cmd))
145 }
146 Log("RULE: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900147 ev.curRule.cmds = cmds
148 ev.outRules = append(ev.outRules, ev.curRule)
149 ev.curRule = nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900150}
151
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900152func (ev *Evaluator) evalRawExpr(ast *RawExprAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900153 ev.filename = ast.filename
154 ev.lineno = ast.lineno
155
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900156 result := ev.evalExpr(ast.expr)
157 if result != "" {
Shinichiro Hamaji91b105c2015-03-30 18:39:05 +0900158 // TODO: Fix rule_in_var.mk.
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900159 fmt.Printf("%s:%d: *** missing separator. Stop.\n", ast.filename, ast.lineno)
160 }
161}
162
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900163func (ev *Evaluator) getVars() map[string]string {
164 vars := make(map[string]string)
165 for k, v := range ev.vars {
166 vars[k] = v
167 }
168 for k, v := range ev.outVars {
169 vars[k] = v
170 }
171 return vars
172}
173
174func (ev *Evaluator) evalInclude(ast *IncludeAST) {
175 ev.filename = ast.filename
176 ev.lineno = ast.lineno
177
178 // TODO: Handle glob
179 files := strings.Split(ev.evalExpr(ast.expr), " ")
180 for _, file := range files {
181 mk, err := ParseMakefile(file)
182 if err != nil {
183 if ast.op == "include" {
184 panic(err)
185 } else {
186 continue
187 }
188 }
189
190 er, err2 := Eval(mk, ev.getVars())
191 if err2 != nil {
192 panic(err2)
193 }
194
195 for k, v := range er.vars {
196 ev.outVars[k] = v
197 }
198 for _, r := range er.rules {
199 ev.outRules = append(ev.outRules, r)
200 }
201 for r, _ := range er.refs {
202 ev.refs[r] = true
203 }
204 }
205}
206
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900207func (ev *Evaluator) eval(ast AST) {
Fumitoshi Ukaie34c1792015-03-30 17:53:47 +0900208 ast.eval(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900209}
210
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900211func Eval(mk Makefile, vars map[string]string) (er *EvalResult, err error) {
212 ev := newEvaluator(vars)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900213 defer func() {
214 if r := recover(); r != nil {
215 err = fmt.Errorf("panic: %v", r)
216 }
217 }()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900218 for _, stmt := range mk.stmts {
219 ev.eval(stmt)
220 }
221 return &EvalResult{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900222 vars: ev.outVars,
223 rules: ev.outRules,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900224 refs: ev.refs,
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900225 }, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900226}