blob: baa36cf811d5b86ff48b4231e8f756be87b5cd5a [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 "os/exec"
7 "path/filepath"
8 "regexp"
9 "strings"
10)
11
12type Rule struct {
13 output string
14 inputs []string
15 cmds []string
16}
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
31 filename string
32 lineno int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090033}
34
35func newEvaluator() *Evaluator {
36 return &Evaluator{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090037 outVars: make(map[string]string),
38 refs: make(map[string]bool),
39 vars: make(map[string]string),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090040 }
41}
42
43func (ev *Evaluator) evalFunction(ex string) (string, bool) {
44 if strings.HasPrefix(ex, "wildcard ") {
45 arg := ex[len("wildcard "):]
46
47 files, err := filepath.Glob(arg)
48 if err != nil {
49 panic(err)
50 }
51 return strings.Join(files, " "), true
52 } else if strings.HasPrefix(ex, "shell ") {
53 arg := ex[len("shell "):]
54
55 args := []string{"/bin/sh", "-c", arg}
56 cmd := exec.Cmd{
57 Path: args[0],
58 Args: args,
59 }
60 out, err := cmd.CombinedOutput()
61 if err != nil {
62 panic(err)
63 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090064 re, err := regexp.Compile(`\s`)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090065 if err != nil {
66 panic(err)
67 }
68 return string(re.ReplaceAllString(string(out), " ")), true
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +090069 } else if strings.HasPrefix(ex, "warning ") {
70 arg := ex[len("warning "):]
71 fmt.Printf("%s:%d: %s\n", ev.filename, ev.lineno, arg)
72 return "", true
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090073 }
74 return "", false
75}
76
77func (ev *Evaluator) evalExprSlice(ex string, term byte) (string, int) {
78 var buf bytes.Buffer
79 i := 0
80 for i < len(ex) && ex[i] != term {
81 ch := ex[i]
82 i++
83 switch ch {
84 case '$':
85 if i >= len(ex) || ex[i] == term {
86 continue
87 }
88
89 var varname string
90 switch ex[i] {
91 case '@':
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090092 buf.WriteString(ev.curRule.output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090093 i++
94 continue
95 case '(':
96 v, j := ev.evalExprSlice(ex[i+1:], ')')
97 i += j + 2
98 if r, done := ev.evalFunction(v); done {
99 buf.WriteString(r)
100 continue
101 }
102
103 varname = v
104 default:
105 varname = string(ex[i])
106 i++
107 }
108
109 value, present := ev.vars[varname]
110 if !present {
111 ev.refs[varname] = true
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900112 value = ev.outVars[varname]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900113 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900114 buf.WriteString(ev.evalExpr(value))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900115
116 default:
117 buf.WriteByte(ch)
118 }
119 }
120 return buf.String(), i
121}
122
123func (ev *Evaluator) evalExpr(ex string) string {
124 r, i := ev.evalExprSlice(ex, 0)
125 if len(ex) != i {
126 panic("Had a null character?")
127 }
128 return r
129}
130
131func (ev *Evaluator) evalAssign(ast *AssignAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900132 ev.filename = ast.filename
133 ev.lineno = ast.lineno
134
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900135 lhs := ev.evalExpr(ast.lhs)
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900136 rhs := ast.evalRHS(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900137 Log("ASSIGN: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900138 ev.outVars[lhs] = rhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900139}
140
141func (ev *Evaluator) evalRule(ast *RuleAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900142 ev.filename = ast.filename
143 ev.lineno = ast.lineno
144
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900145 ev.curRule = &Rule{}
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900146 lhs := ev.evalExpr(ast.lhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900147 ev.curRule.output = lhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900148 rhs := ev.evalExpr(ast.rhs)
149 if rhs != "" {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900150 ev.curRule.inputs = strings.Split(rhs, " ")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900151 }
152 var cmds []string
153 for _, cmd := range ast.cmds {
154 cmds = append(cmds, ev.evalExpr(cmd))
155 }
156 Log("RULE: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900157 ev.curRule.cmds = cmds
158 ev.outRules = append(ev.outRules, ev.curRule)
159 ev.curRule = nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900160}
161
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900162func (ev *Evaluator) evalRawExpr(ast *RawExprAST) {
Shinichiro Hamaji51d53d92015-03-30 18:32:16 +0900163 ev.filename = ast.filename
164 ev.lineno = ast.lineno
165
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900166 result := ev.evalExpr(ast.expr)
167 if result != "" {
Shinichiro Hamaji91b105c2015-03-30 18:39:05 +0900168 // TODO: Fix rule_in_var.mk.
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900169 fmt.Printf("%s:%d: *** missing separator. Stop.\n", ast.filename, ast.lineno)
170 }
171}
172
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900173func (ev *Evaluator) eval(ast AST) {
Fumitoshi Ukaie34c1792015-03-30 17:53:47 +0900174 ast.eval(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900175}
176
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900177func Eval(mk Makefile) (er *EvalResult, err error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900178 ev := newEvaluator()
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900179 defer func() {
180 if r := recover(); r != nil {
181 err = fmt.Errorf("panic: %v", r)
182 }
183 }()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900184 for _, stmt := range mk.stmts {
185 ev.eval(stmt)
186 }
187 return &EvalResult{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900188 vars: ev.outVars,
189 rules: ev.outRules,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900190 refs: ev.refs,
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900191 }, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900192}