blob: 040995a4795743e8205560525fc4ee42caaf7afd [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
34func newEvaluator() *Evaluator {
35 return &Evaluator{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090036 outVars: make(map[string]string),
37 refs: make(map[string]bool),
38 vars: make(map[string]string),
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
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900156func (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
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900160func Eval(mk Makefile) (er *EvalResult, err error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900161 ev := newEvaluator()
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900162 defer func() {
163 if r := recover(); r != nil {
164 err = fmt.Errorf("panic: %v", r)
165 }
166 }()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900167 for _, stmt := range mk.stmts {
168 ev.eval(stmt)
169 }
170 return &EvalResult{
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900171 vars: ev.outVars,
172 rules: ev.outRules,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900173 refs: ev.refs,
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900174 }, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900175}