blob: c025307e6fdbeeeb1f89751185752e5d016f2cd5 [file] [log] [blame]
Shinichiro Hamajib69bf8a2015-06-10 14:52:06 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015package kati
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090016
Fumitoshi Ukai0aa4fc42015-04-10 17:00:19 +090017//go:generate go run testcase/gen_testcase_parse_benchmark.go
18//
19// $ go generate
20// $ go test -bench .
21
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090022import (
23 "bufio"
Shinichiro Hamajie1841582015-03-30 17:20:33 +090024 "bytes"
Fumitoshi Ukai9042b992015-06-23 16:10:27 +090025 "crypto/sha1"
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090026 "errors"
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +090027 "fmt"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090028 "io"
Fumitoshi Ukai9042b992015-06-23 16:10:27 +090029 "io/ioutil"
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090030 "strings"
Fumitoshi Ukai9042b992015-06-23 16:10:27 +090031 "sync"
Shinichiro Hamaji584bb062015-06-04 13:25:13 +090032 "time"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090033)
34
Fumitoshi Ukai08eda652015-06-25 16:27:10 +090035type makefile struct {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090036 filename string
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +090037 stmts []ast
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090038}
39
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090040type ifState struct {
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +090041 ast *ifAST
Shinichiro Hamajia06760f2015-04-07 13:13:45 +090042 inElse bool
43 numNest int
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090044}
45
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090046type parser struct {
Shinichiro Hamaji370be722015-04-10 14:55:23 +090047 rd *bufio.Reader
Fumitoshi Ukai08eda652015-06-25 16:27:10 +090048 mk makefile
Shinichiro Hamaji370be722015-04-10 14:55:23 +090049 lineno int
50 elineno int // lineno == elineno unless there is trailing '\'.
51 linenoFixed bool
Shinichiro Hamaji370be722015-04-10 14:55:23 +090052 done bool
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +090053 outStmts *[]ast
Shinichiro Hamaji370be722015-04-10 14:55:23 +090054 ifStack []ifState
55 inDef []string
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +090056 defOpt string
Shinichiro Hamaji370be722015-04-10 14:55:23 +090057 numIfNest int
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090058 err error
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090059}
60
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +090061func newParser(rd io.Reader, filename string) *parser {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090062 p := &parser{
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +090063 rd: bufio.NewReader(rd),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090064 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090065 p.mk.filename = filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090066 p.outStmts = &p.mk.stmts
67 return p
68}
69
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090070func (p *parser) srcpos() srcpos {
71 return srcpos{
72 filename: p.mk.filename,
73 lineno: p.lineno,
74 }
75}
76
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +090077func (p *parser) addStatement(stmt ast) {
78 *p.outStmts = append(*p.outStmts, stmt)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090079}
80
Shinichiro Hamajie1841582015-03-30 17:20:33 +090081func (p *parser) readLine() []byte {
Shinichiro Hamaji370be722015-04-10 14:55:23 +090082 if !p.linenoFixed {
83 p.lineno = p.elineno
84 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +090085 line, err := p.rd.ReadBytes('\n')
Shinichiro Hamaji370be722015-04-10 14:55:23 +090086 if !p.linenoFixed {
87 p.lineno++
88 p.elineno = p.lineno
89 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +090090 if err == io.EOF {
91 p.done = true
92 } else if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090093 p.err = fmt.Errorf("readline %s: %v", p.srcpos(), err)
94 p.done = true
Shinichiro Hamajie1841582015-03-30 17:20:33 +090095 }
96
Shinichiro Hamaji56c868c2015-04-09 10:17:10 +090097 line = bytes.TrimRight(line, "\r\n")
Shinichiro Hamajie1841582015-03-30 17:20:33 +090098
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +090099 return line
100}
101
102func removeComment(line []byte) []byte {
103 var parenStack []byte
Shinichiro Hamajif4d3ee52015-04-22 16:19:33 +0900104 // Do not use range as we may modify |line| and |i|.
105 for i := 0; i < len(line); i++ {
106 ch := line[i]
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900107 switch ch {
108 case '(', '{':
109 parenStack = append(parenStack, ch)
110 case ')', '}':
111 if len(parenStack) > 0 {
Shinichiro Hamajif863d862015-06-17 16:48:37 +0900112 cp := closeParen(parenStack[len(parenStack)-1])
113 if cp == ch {
114 parenStack = parenStack[:len(parenStack)-1]
115 }
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900116 }
117 case '#':
118 if len(parenStack) == 0 {
Shinichiro Hamajif4d3ee52015-04-22 16:19:33 +0900119 if i == 0 || line[i-1] != '\\' {
120 return line[:i]
121 }
122 // Drop the backslash before '#'.
123 line = append(line[:i-1], line[i:]...)
124 i--
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900125 }
126 }
127 }
128 return line
129}
130
Shinichiro Hamajie2f6e902015-04-22 16:08:47 +0900131func hasTrailingBackslash(line []byte) bool {
132 if len(line) == 0 {
133 return false
134 }
135 if line[len(line)-1] != '\\' {
136 return false
137 }
138 return len(line) <= 1 || line[len(line)-2] != '\\'
139}
140
Shinichiro Hamajie52c16c2015-04-11 23:41:39 +0900141func (p *parser) processDefineLine(line []byte) []byte {
Shinichiro Hamajie2f6e902015-04-22 16:08:47 +0900142 for hasTrailingBackslash(line) {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900143 line = line[:len(line)-1]
Shinichiro Hamajic4c98102015-04-12 03:56:00 +0900144 line = bytes.TrimRight(line, "\t ")
Shinichiro Hamaji3e4533d2015-04-06 14:03:58 +0900145 lineno := p.lineno
Shinichiro Hamajic4c98102015-04-12 03:56:00 +0900146 nline := trimLeftSpaceBytes(p.readLine())
Shinichiro Hamaji3e4533d2015-04-06 14:03:58 +0900147 p.lineno = lineno
Shinichiro Hamajic4c98102015-04-12 03:56:00 +0900148 line = append(line, ' ')
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900149 line = append(line, nline...)
150 }
Shinichiro Hamajie52c16c2015-04-11 23:41:39 +0900151 return line
152}
153
154func (p *parser) processMakefileLine(line []byte) []byte {
155 return removeComment(p.processDefineLine(line))
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900156}
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900157
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900158func (p *parser) processRecipeLine(line []byte) []byte {
Shinichiro Hamajie2f6e902015-04-22 16:08:47 +0900159 for hasTrailingBackslash(line) {
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900160 line = append(line, '\n')
161 lineno := p.lineno
162 nline := p.readLine()
163 p.lineno = lineno
164 line = append(line, nline...)
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900165 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900166 return line
167}
168
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900169func newAssignAST(p *parser, lhsBytes []byte, rhsBytes []byte, op string) (*assignAST, error) {
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900170 lhs, _, err := parseExpr(lhsBytes, nil, true)
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900171 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900172 return nil, err
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900173 }
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900174 rhs, _, err := parseExpr(rhsBytes, nil, true)
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900175 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900176 return nil, err
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900177 }
178 opt := ""
179 if p != nil {
180 opt = p.defOpt
181 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900182 return &assignAST{
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900183 lhs: lhs,
184 rhs: rhs,
185 op: op,
186 opt: opt,
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900187 }, nil
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900188}
189
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900190func (p *parser) parseAssign(line []byte, sep, esep int) (ast, error) {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900191 logf("parseAssign %q op:%q", line, line[sep:esep])
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900192 aast, err := newAssignAST(p, bytes.TrimSpace(line[:sep]), trimLeftSpaceBytes(line[esep:]), string(line[sep:esep]))
193 if err != nil {
194 return nil, err
195 }
196 aast.srcpos = p.srcpos()
197 return aast, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900198}
199
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900200func (p *parser) parseMaybeRule(line []byte, equalIndex, semicolonIndex int) (ast, error) {
Shinichiro Hamaji50309a62015-06-04 14:01:55 +0900201 if len(trimSpaceBytes(line)) == 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900202 return nil, nil
Shinichiro Hamajide829712015-03-31 18:26:56 +0900203 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900204
Shinichiro Hamaji171a3df2015-06-04 14:17:45 +0900205 expr := line
206 var term byte
207 var afterTerm []byte
208
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900209 // Either '=' or ';' is used.
210 if equalIndex >= 0 && semicolonIndex >= 0 {
211 if equalIndex < semicolonIndex {
212 semicolonIndex = -1
213 } else {
214 equalIndex = -1
215 }
216 }
Shinichiro Hamaji171a3df2015-06-04 14:17:45 +0900217 if semicolonIndex >= 0 {
218 afterTerm = expr[semicolonIndex:]
219 expr = expr[0:semicolonIndex]
220 term = ';'
221 } else if equalIndex >= 0 {
222 afterTerm = expr[equalIndex:]
223 expr = expr[0:equalIndex]
224 term = '='
225 }
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900226
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900227 v, _, err := parseExpr(expr, nil, true)
Shinichiro Hamaji2d4b6052015-06-04 14:20:44 +0900228 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900229 return nil, p.srcpos().error(err)
Shinichiro Hamaji2d4b6052015-06-04 14:20:44 +0900230 }
231
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900232 rast := &maybeRuleAST{
Shinichiro Hamaji2d4b6052015-06-04 14:20:44 +0900233 expr: v,
Shinichiro Hamaji171a3df2015-06-04 14:17:45 +0900234 term: term,
235 afterTerm: afterTerm,
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900236 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900237 rast.srcpos = p.srcpos()
238 return rast, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900239}
240
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900241func (p *parser) parseInclude(line string, oplen int) {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900242 // TODO(ukai): parse expr here
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900243 iast := &includeAST{
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900244 expr: line[oplen+1:],
245 op: line[:oplen],
246 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900247 iast.srcpos = p.srcpos()
248 p.addStatement(iast)
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900249}
250
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900251func (p *parser) parseIfdef(line []byte, oplen int) {
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900252 lhs, _, err := parseExpr(trimLeftSpaceBytes(line[oplen+1:]), nil, true)
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900253 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900254 p.err = p.srcpos().error(err)
255 return
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900256 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900257 iast := &ifAST{
Shinichiro Hamaji61d2e112015-06-04 14:56:47 +0900258 op: string(line[:oplen]),
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900259 lhs: lhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900260 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900261 iast.srcpos = p.srcpos()
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900262 p.addStatement(iast)
263 p.ifStack = append(p.ifStack, ifState{ast: iast, numNest: p.numIfNest})
264 p.outStmts = &iast.trueStmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900265}
266
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900267func (p *parser) parseTwoQuotes(s string, op string) ([]string, bool, error) {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900268 var args []string
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900269 for i := 0; i < 2; i++ {
270 s = strings.TrimSpace(s)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900271 if s == "" {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900272 return nil, false, nil
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900273 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900274 quote := s[0]
275 if quote != '\'' && quote != '"' {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900276 return nil, false, nil
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900277 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900278 end := strings.IndexByte(s[1:], quote) + 1
279 if end < 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900280 return nil, false, nil
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900281 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900282 args = append(args, s[1:end])
283 s = s[end+1:]
284 }
285 if len(s) > 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900286 return nil, false, p.srcpos().errorf(`extraneous text after %q directive`, op)
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900287 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900288 return args, true, nil
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900289}
290
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900291// parse
292// "(lhs, rhs)"
293// "lhs, rhs"
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900294func (p *parser) parseEq(s string, op string) (string, string, bool, error) {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900295 if s[0] == '(' && s[len(s)-1] == ')' {
296 s = s[1 : len(s)-1]
297 term := []byte{','}
298 in := []byte(s)
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900299 v, n, err := parseExpr(in, term, false)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900300 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900301 return "", "", false, err
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900302 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900303 lhs := v.String()
304 n++
305 n += skipSpaces(in[n:], nil)
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900306 v, n, err = parseExpr(in[n:], nil, false)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900307 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900308 return "", "", false, err
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900309 }
310 rhs := v.String()
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900311 return lhs, rhs, true, nil
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900312 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900313 args, ok, err := p.parseTwoQuotes(s, op)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900314 if !ok {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900315 return "", "", false, err
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900316 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900317 return args[0], args[1], true, nil
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900318}
319
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900320func (p *parser) parseIfeq(line string, oplen int) {
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900321 op := line[:oplen]
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900322 lhsBytes, rhsBytes, ok, err := p.parseEq(strings.TrimSpace(line[oplen+1:]), op)
323 if err != nil {
324 p.err = err
325 return
326 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900327 if !ok {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900328 p.err = p.srcpos().errorf(`*** invalid syntax in conditional.`)
329 return
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900330 }
331
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900332 lhs, _, err := parseExpr([]byte(lhsBytes), nil, true)
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900333 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900334 p.err = p.srcpos().error(err)
335 return
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900336 }
Fumitoshi Ukai7c9aa9f2015-06-12 23:51:38 +0900337 rhs, _, err := parseExpr([]byte(rhsBytes), nil, true)
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900338 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900339 p.err = p.srcpos().error(err)
340 return
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900341 }
342
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900343 iast := &ifAST{
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900344 op: op,
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900345 lhs: lhs,
346 rhs: rhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900347 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900348 iast.srcpos = p.srcpos()
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900349 p.addStatement(iast)
350 p.ifStack = append(p.ifStack, ifState{ast: iast, numNest: p.numIfNest})
351 p.outStmts = &iast.trueStmts
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900352 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900353}
354
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900355func (p *parser) checkIfStack(curKeyword string) error {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900356 if len(p.ifStack) == 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900357 return p.srcpos().errorf(`*** extraneous %q.`, curKeyword)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900358 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900359 return nil
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900360}
361
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900362func (p *parser) parseElse(line []byte) {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900363 err := p.checkIfStack("else")
364 if err != nil {
365 p.err = err
366 return
367 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900368 state := &p.ifStack[len(p.ifStack)-1]
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900369 if state.inElse {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900370 p.err = p.srcpos().errorf(`*** only one "else" per conditional.`)
371 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900372 }
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900373 state.inElse = true
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900374 p.outStmts = &state.ast.falseStmts
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900375
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900376 nextIf := trimLeftSpaceBytes(line[len("else"):])
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900377 if len(nextIf) == 0 {
378 return
379 }
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900380 var ifDirectives = map[string]directiveFunc{
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900381 "ifdef ": ifdefDirective,
382 "ifndef ": ifndefDirective,
383 "ifeq ": ifeqDirective,
384 "ifneq ": ifneqDirective,
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900385 }
386 p.numIfNest = state.numNest + 1
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900387 if f, ok := p.isDirective(nextIf, ifDirectives); ok {
388 f(p, nextIf)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900389 p.numIfNest = 0
390 return
391 }
392 p.numIfNest = 0
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900393 warnNoPrefix(p.srcpos(), "extraneous text after `else` directive")
394 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900395}
396
397func (p *parser) parseEndif(line string) {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900398 err := p.checkIfStack("endif")
399 if err != nil {
400 p.err = err
401 return
402 }
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900403 state := p.ifStack[len(p.ifStack)-1]
404 for t := 0; t <= state.numNest; t++ {
405 p.ifStack = p.ifStack[0 : len(p.ifStack)-1]
406 if len(p.ifStack) == 0 {
407 p.outStmts = &p.mk.stmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900408 } else {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900409 state := p.ifStack[len(p.ifStack)-1]
410 if state.inElse {
411 p.outStmts = &state.ast.falseStmts
412 } else {
413 p.outStmts = &state.ast.trueStmts
414 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900415 }
416 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900417 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900418}
419
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900420type directiveFunc func(*parser, []byte) []byte
421
422var makeDirectives = map[string]directiveFunc{
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900423 "include ": includeDirective,
424 "-include ": sincludeDirective,
425 "sinclude": sincludeDirective,
426 "ifdef ": ifdefDirective,
427 "ifndef ": ifndefDirective,
428 "ifeq ": ifeqDirective,
429 "ifneq ": ifneqDirective,
430 "else": elseDirective,
431 "endif": endifDirective,
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900432 "define ": defineDirective,
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900433 "override ": overrideDirective,
434 "export ": exportDirective,
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900435 "unexport ": unexportDirective,
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900436}
437
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900438// TODO(ukai): use []byte
439func (p *parser) isDirective(line []byte, directives map[string]directiveFunc) (directiveFunc, bool) {
440 stripped := trimLeftSpaceBytes(line)
Shinichiro Hamajie103f652015-04-11 19:49:51 +0900441 // Fast paths.
442 // TODO: Consider using a trie.
443 if len(stripped) == 0 {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900444 return nil, false
Shinichiro Hamajie103f652015-04-11 19:49:51 +0900445 }
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900446 if ch := stripped[0]; ch != 'i' && ch != '-' && ch != 's' && ch != 'e' && ch != 'd' && ch != 'o' && ch != 'u' {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900447 return nil, false
Shinichiro Hamajie103f652015-04-11 19:49:51 +0900448 }
449
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900450 for prefix, f := range directives {
451 if bytes.HasPrefix(stripped, []byte(prefix)) {
452 return f, true
453 }
Fumitoshi Ukai37cdaba2015-06-30 17:35:14 +0900454 if prefix[len(prefix)-1] == ' ' && bytes.HasPrefix(stripped, []byte(prefix[:len(prefix)-1])) && len(stripped) >= len(prefix) && stripped[len(prefix)-1] == '\t' {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900455 return f, true
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900456 }
457 }
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900458 return nil, false
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900459}
460
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900461func includeDirective(p *parser, line []byte) []byte {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900462 p.parseInclude(string(line), len("include"))
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900463 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900464}
465
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900466func sincludeDirective(p *parser, line []byte) []byte {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900467 p.parseInclude(string(line), len("-include"))
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900468 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900469}
470
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900471func ifdefDirective(p *parser, line []byte) []byte {
Shinichiro Hamaji61d2e112015-06-04 14:56:47 +0900472 p.parseIfdef(line, len("ifdef"))
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900473 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900474}
475
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900476func ifndefDirective(p *parser, line []byte) []byte {
Shinichiro Hamaji61d2e112015-06-04 14:56:47 +0900477 p.parseIfdef(line, len("ifndef"))
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900478 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900479}
480
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900481func ifeqDirective(p *parser, line []byte) []byte {
482 p.parseIfeq(string(line), len("ifeq"))
483 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900484}
485
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900486func ifneqDirective(p *parser, line []byte) []byte {
487 p.parseIfeq(string(line), len("ifneq"))
488 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900489}
490
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900491func elseDirective(p *parser, line []byte) []byte {
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900492 p.parseElse(line)
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900493 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900494}
495
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900496func endifDirective(p *parser, line []byte) []byte {
497 p.parseEndif(string(line))
498 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900499}
500
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900501func defineDirective(p *parser, line []byte) []byte {
Shinichiro Hamaji72ae2dd2015-06-17 15:47:15 +0900502 lhs := trimLeftSpaceBytes(line[len("define "):])
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900503 p.inDef = []string{string(lhs)}
504 return nil
505}
506
507func overrideDirective(p *parser, line []byte) []byte {
508 p.defOpt = "override"
509 line = trimLeftSpaceBytes(line[len("override "):])
510 defineDirective := map[string]directiveFunc{
511 "define": defineDirective,
512 }
513 if f, ok := p.isDirective(line, defineDirective); ok {
514 f(p, line)
515 return nil
516 }
517 // e.g. overrider foo := bar
518 // line will be "foo := bar".
519 return line
520}
521
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900522func handleExport(p *parser, line []byte, export bool) (hasEqual bool) {
523 equalIndex := bytes.IndexByte(line, '=')
524 if equalIndex > 0 {
525 hasEqual = true
526 switch line[equalIndex-1] {
527 case ':', '+', '?':
528 equalIndex--
529 }
530 line = line[:equalIndex]
531 }
532
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900533 east := &exportAST{
Shinichiro Hamajif61033d2015-05-29 15:01:48 +0900534 expr: line,
535 export: export,
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900536 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900537 east.srcpos = p.srcpos()
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900538 p.addStatement(east)
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900539 return hasEqual
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900540}
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900541
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900542func exportDirective(p *parser, line []byte) []byte {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900543 p.defOpt = "export"
544 line = trimLeftSpaceBytes(line[len("export "):])
545 defineDirective := map[string]directiveFunc{
546 "define": defineDirective,
547 }
548 if f, ok := p.isDirective(line, defineDirective); ok {
549 f(p, line)
550 return nil
551 }
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900552
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900553 if !handleExport(p, line, true) {
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900554 return nil
555 }
556
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900557 // e.g. export foo := bar
558 // line will be "foo := bar".
559 return line
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900560}
561
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900562func unexportDirective(p *parser, line []byte) []byte {
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900563 handleExport(p, line[len("unexport "):], false)
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900564 return nil
565}
566
Shinichiro Hamajica668572015-06-17 06:36:45 +0900567func (p *parser) isEndef(s string) bool {
568 if s == "endef" {
569 return true
570 }
571 found := strings.IndexAny(s, " \t")
572 if found >= 0 && s[:found] == "endef" {
573 rest := strings.TrimSpace(s[found+1:])
574 if rest != "" && rest[0] != '#' {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900575 warnNoPrefix(p.srcpos(), "extraneous text after \"endef\" directive")
Shinichiro Hamajica668572015-06-17 06:36:45 +0900576 }
577 return true
578 }
579 return false
580}
581
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900582func (p *parser) parse() (mk makefile, err error) {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900583 for !p.done {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900584 line := p.readLine()
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900585
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900586 if len(p.inDef) > 0 {
Shinichiro Hamajica668572015-06-17 06:36:45 +0900587 lineStr := string(p.processDefineLine(line))
588 if p.isEndef(lineStr) {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900589 logf("multilineAssign %q", p.inDef)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900590 aast, err := newAssignAST(p, []byte(p.inDef[0]), []byte(strings.Join(p.inDef[1:], "\n")), "=")
591 if err != nil {
592 return makefile{}, err
593 }
594 aast.srcpos = p.srcpos()
595 aast.srcpos.lineno -= len(p.inDef)
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900596 p.addStatement(aast)
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900597 p.inDef = nil
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900598 p.defOpt = ""
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900599 continue
600 }
Shinichiro Hamajica668572015-06-17 06:36:45 +0900601 p.inDef = append(p.inDef, lineStr)
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900602 continue
603 }
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900604 p.defOpt = ""
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900605
Shinichiro Hamaji960161f2015-04-13 17:10:10 +0900606 if len(bytes.TrimSpace(line)) == 0 {
607 continue
608 }
609
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900610 if f, ok := p.isDirective(line, makeDirectives); ok {
Shinichiro Hamaji72ae2dd2015-06-17 15:47:15 +0900611 line = trimSpaceBytes(p.processMakefileLine(line))
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900612 line = f(p, line)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900613 if p.err != nil {
614 return makefile{}, p.err
615 }
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900616 if len(line) == 0 {
617 continue
618 }
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900619 }
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900620 if line[0] == '\t' {
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900621 cast := &commandAST{cmd: string(p.processRecipeLine(line[1:]))}
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900622 cast.srcpos = p.srcpos()
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900623 p.addStatement(cast)
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900624 continue
625 }
626
627 line = p.processMakefileLine(line)
Shinichiro Hamajia66a1792015-03-31 18:04:08 +0900628
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900629 var stmt ast
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900630 var parenStack []byte
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900631 equalIndex := -1
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900632 semicolonIndex := -1
633 isRule := false
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900634 for i, ch := range line {
635 switch ch {
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900636 case '(', '{':
637 parenStack = append(parenStack, ch)
638 case ')', '}':
639 if len(parenStack) == 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900640 warn(p.srcpos(), "Unmatched parens: %s", line)
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900641 } else {
Shinichiro Hamajif863d862015-06-17 16:48:37 +0900642 cp := closeParen(parenStack[len(parenStack)-1])
643 if cp == ch {
644 parenStack = parenStack[:len(parenStack)-1]
645 }
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900646 }
647 }
648 if len(parenStack) > 0 {
649 continue
650 }
651
652 switch ch {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900653 case ':':
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900654 if i+1 < len(line) && line[i+1] == '=' {
Shinichiro Hamaji156ef3e2015-04-11 22:44:41 +0900655 if !isRule {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900656 stmt, err = p.parseAssign(line, i, i+2)
657 if err != nil {
658 return makefile{}, err
659 }
Shinichiro Hamaji156ef3e2015-04-11 22:44:41 +0900660 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900661 } else {
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900662 isRule = true
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900663 }
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900664 case ';':
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900665 if semicolonIndex < 0 {
666 semicolonIndex = i
667 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900668 case '=':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900669 if !isRule {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900670 stmt, err = p.parseAssign(line, i, i+1)
671 if err != nil {
672 return makefile{}, err
673 }
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900674 }
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900675 if equalIndex < 0 {
676 equalIndex = i
677 }
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900678 case '?', '+':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900679 if !isRule && i+1 < len(line) && line[i+1] == '=' {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900680 stmt, err = p.parseAssign(line, i, i+2)
681 if err != nil {
682 return makefile{}, err
683 }
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900684 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900685 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900686 if stmt != nil {
687 p.addStatement(stmt)
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900688 break
689 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900690 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900691 if stmt == nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900692 stmt, err = p.parseMaybeRule(line, equalIndex, semicolonIndex)
693 if err != nil {
694 return makefile{}, err
695 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900696 if stmt != nil {
697 p.addStatement(stmt)
Shinichiro Hamajide829712015-03-31 18:26:56 +0900698 }
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900699 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900700 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900701 return p.mk, p.err
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900702}
703
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900704func defaultMakefile() (string, error) {
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900705 candidates := []string{"GNUmakefile", "makefile", "Makefile"}
706 for _, filename := range candidates {
707 if exists(filename) {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900708 return filename, nil
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900709 }
710 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900711 return "", errors.New("no targets specified and no makefile found")
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900712}
713
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900714func parseMakefileReader(rd io.Reader, loc srcpos) (makefile, error) {
715 parser := newParser(rd, loc.filename)
716 parser.lineno = loc.lineno
717 parser.elineno = loc.lineno
Shinichiro Hamaji370be722015-04-10 14:55:23 +0900718 parser.linenoFixed = true
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900719 return parser.parse()
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900720}
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900721
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900722func parseMakefileString(s string, loc srcpos) (makefile, error) {
723 return parseMakefileReader(strings.NewReader(s), loc)
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900724}
725
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900726func parseMakefileBytes(s []byte, loc srcpos) (makefile, error) {
727 return parseMakefileReader(bytes.NewReader(s), loc)
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900728}
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900729
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900730type mkCacheEntry struct {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900731 mk makefile
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900732 hash [sha1.Size]byte
733 err error
734 ts int64
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900735}
736
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900737type makefileCacheT struct {
738 mu sync.Mutex
739 mk map[string]mkCacheEntry
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900740}
741
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900742var makefileCache = &makefileCacheT{
743 mk: make(map[string]mkCacheEntry),
744}
745
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900746func (mc *makefileCacheT) lookup(filename string) (makefile, [sha1.Size]byte, bool, error) {
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900747 var hash [sha1.Size]byte
748 mc.mu.Lock()
749 c, present := mc.mk[filename]
750 mc.mu.Unlock()
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900751 if !present {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900752 return makefile{}, hash, false, nil
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900753 }
754 ts := getTimestamp(filename)
755 if ts < 0 || ts >= c.ts {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900756 return makefile{}, hash, false, nil
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900757 }
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900758 return c.mk, c.hash, true, c.err
759}
760
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900761func (mc *makefileCacheT) parse(filename string) (makefile, [sha1.Size]byte, error) {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900762 logf("parse Makefile %q", filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900763 mk, hash, ok, err := makefileCache.lookup(filename)
764 if ok {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900765 if LogFlag {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900766 logf("makefile cache hit for %q", filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900767 }
768 return mk, hash, err
769 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900770 if LogFlag {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900771 logf("reading makefile %q", filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900772 }
773 c, err := ioutil.ReadFile(filename)
774 if err != nil {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900775 return makefile{}, hash, err
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900776 }
777 hash = sha1.Sum(c)
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900778 mk, err = parseMakefile(c, filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900779 if err != nil {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900780 return makefile{}, hash, err
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900781 }
782 makefileCache.mu.Lock()
783 makefileCache.mk[filename] = mkCacheEntry{
784 mk: mk,
785 hash: hash,
786 err: err,
787 ts: time.Now().Unix(),
788 }
789 makefileCache.mu.Unlock()
790 return mk, hash, err
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900791}
792
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900793func parseMakefile(s []byte, filename string) (makefile, error) {
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900794 parser := newParser(bytes.NewReader(s), filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900795 return parser.parse()
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900796}