blob: 9c8427d16ce32ae18d7e1114f4ad4dfd9476d475 [file] [log] [blame]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09001package main
2
3import (
4 "bytes"
5 "os/exec"
6 "path/filepath"
7 "regexp"
8 "strings"
9)
10
11type Rule struct {
12 output string
13 inputs []string
14 cmds []string
15}
16
17type EvalResult struct {
18 vars map[string]string
19 rules []*Rule
20 refs map[string]bool
21}
22
23type Evaluator struct {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090024 outVars map[string]string
25 outRules []*Rule
26 refs map[string]bool
27 vars map[string]string
28 curRule *Rule
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090029}
30
31func newEvaluator() *Evaluator {
32 return &Evaluator{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090033 outVars: make(map[string]string),
34 refs: make(map[string]bool),
35 vars: make(map[string]string),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090036 }
37}
38
39func (ev *Evaluator) evalFunction(ex string) (string, bool) {
40 if strings.HasPrefix(ex, "wildcard ") {
41 arg := ex[len("wildcard "):]
42
43 files, err := filepath.Glob(arg)
44 if err != nil {
45 panic(err)
46 }
47 return strings.Join(files, " "), true
48 } else if strings.HasPrefix(ex, "shell ") {
49 arg := ex[len("shell "):]
50
51 args := []string{"/bin/sh", "-c", arg}
52 cmd := exec.Cmd{
53 Path: args[0],
54 Args: args,
55 }
56 out, err := cmd.CombinedOutput()
57 if err != nil {
58 panic(err)
59 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090060 re, err := regexp.Compile(`\s`)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090061 if err != nil {
62 panic(err)
63 }
64 return string(re.ReplaceAllString(string(out), " ")), true
65 }
66 return "", false
67}
68
69func (ev *Evaluator) evalExprSlice(ex string, term byte) (string, int) {
70 var buf bytes.Buffer
71 i := 0
72 for i < len(ex) && ex[i] != term {
73 ch := ex[i]
74 i++
75 switch ch {
76 case '$':
77 if i >= len(ex) || ex[i] == term {
78 continue
79 }
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
87 case '(':
88 v, j := ev.evalExprSlice(ex[i+1:], ')')
89 i += j + 2
90 if r, done := ev.evalFunction(v); done {
91 buf.WriteString(r)
92 continue
93 }
94
95 varname = v
96 default:
97 varname = string(ex[i])
98 i++
99 }
100
101 value, present := ev.vars[varname]
102 if !present {
103 ev.refs[varname] = true
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900104 value = ev.outVars[varname]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900105 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900106 buf.WriteString(ev.evalExpr(value))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900107
108 default:
109 buf.WriteByte(ch)
110 }
111 }
112 return buf.String(), i
113}
114
115func (ev *Evaluator) evalExpr(ex string) string {
116 r, i := ev.evalExprSlice(ex, 0)
117 if len(ex) != i {
118 panic("Had a null character?")
119 }
120 return r
121}
122
123func (ev *Evaluator) evalAssign(ast *AssignAST) {
124 lhs := ev.evalExpr(ast.lhs)
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900125 var rhs string
126 switch ast.assign_type {
127 case ASSIGN_SIMPLE:
128 rhs = ev.evalExpr(ast.rhs)
129 case ASSIGN_RECURSIVE:
130 rhs = ast.rhs
131 default:
132 panic("TODO")
133 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900134 Log("ASSIGN: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900135 ev.outVars[lhs] = rhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900136}
137
138func (ev *Evaluator) evalRule(ast *RuleAST) {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900139 ev.curRule = &Rule{}
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900140 lhs := ev.evalExpr(ast.lhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900141 ev.curRule.output = lhs
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900142 rhs := ev.evalExpr(ast.rhs)
143 if rhs != "" {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900144 ev.curRule.inputs = strings.Split(rhs, " ")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900145 }
146 var cmds []string
147 for _, cmd := range ast.cmds {
148 cmds = append(cmds, ev.evalExpr(cmd))
149 }
150 Log("RULE: %s=%s", lhs, rhs)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900151 ev.curRule.cmds = cmds
152 ev.outRules = append(ev.outRules, ev.curRule)
153 ev.curRule = nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900154}
155
156func (ev *Evaluator) eval(ast AST) {
Fumitoshi Ukaie34c1792015-03-30 17:53:47 +0900157 ast.eval(ev)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900158}
159
160func Eval(mk Makefile) *EvalResult {
161 ev := newEvaluator()
162 for _, stmt := range mk.stmts {
163 ev.eval(stmt)
164 }
165 return &EvalResult{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900166 vars: ev.outVars,
167 rules: ev.outRules,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900168 refs: ev.refs,
169 }
170}