blob: aef20e20ceffe1301e793c5a95664b9d2d20ab10 [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 Ukai6450d0f2015-07-10 16:34:06 +090033
34 "github.com/golang/glog"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090035)
36
Fumitoshi Ukai08eda652015-06-25 16:27:10 +090037type makefile struct {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090038 filename string
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +090039 stmts []ast
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090040}
41
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090042type ifState struct {
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +090043 ast *ifAST
Shinichiro Hamajia06760f2015-04-07 13:13:45 +090044 inElse bool
45 numNest int
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090046}
47
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090048type parser struct {
Shinichiro Hamaji370be722015-04-10 14:55:23 +090049 rd *bufio.Reader
Fumitoshi Ukai08eda652015-06-25 16:27:10 +090050 mk makefile
Shinichiro Hamaji370be722015-04-10 14:55:23 +090051 lineno int
52 elineno int // lineno == elineno unless there is trailing '\'.
53 linenoFixed bool
Shinichiro Hamaji370be722015-04-10 14:55:23 +090054 done bool
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +090055 outStmts *[]ast
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090056 inRecipe bool
Shinichiro Hamaji370be722015-04-10 14:55:23 +090057 ifStack []ifState
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090058
59 defineVar []byte
60 inDef []byte
61
62 defOpt string
63 numIfNest int
64 err error
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090065}
66
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +090067func newParser(rd io.Reader, filename string) *parser {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090068 p := &parser{
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +090069 rd: bufio.NewReader(rd),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090070 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090071 p.mk.filename = filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090072 p.outStmts = &p.mk.stmts
73 return p
74}
75
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090076func (p *parser) srcpos() srcpos {
77 return srcpos{
78 filename: p.mk.filename,
79 lineno: p.lineno,
80 }
81}
82
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +090083func (p *parser) addStatement(stmt ast) {
84 *p.outStmts = append(*p.outStmts, stmt)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090085 switch stmt.(type) {
86 case *maybeRuleAST:
87 p.inRecipe = true
88 case *assignAST, *includeAST, *exportAST:
89 p.inRecipe = false
90 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090091}
92
Shinichiro Hamajie1841582015-03-30 17:20:33 +090093func (p *parser) readLine() []byte {
Shinichiro Hamaji370be722015-04-10 14:55:23 +090094 if !p.linenoFixed {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090095 p.lineno = p.elineno + 1
Shinichiro Hamaji370be722015-04-10 14:55:23 +090096 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090097 var line []byte
98 for !p.done {
99 buf, err := p.rd.ReadBytes('\n')
100 if !p.linenoFixed {
101 p.elineno++
102 }
103 if err == io.EOF {
104 p.done = true
105 } else if err != nil {
106 p.err = fmt.Errorf("readline %s: %v", p.srcpos(), err)
107 p.done = true
108 }
109 line = append(line, buf...)
110 buf = bytes.TrimRight(buf, "\r\n")
Fumitoshi Ukai1d92d8a2015-08-21 17:10:55 +0900111 glog.V(4).Infof("buf:%q", buf)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900112 backslash := false
Fumitoshi Ukai1d92d8a2015-08-21 17:10:55 +0900113 for len(buf) > 0 && buf[len(buf)-1] == '\\' {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900114 buf = buf[:len(buf)-1]
115 backslash = !backslash
116 }
117 if !backslash {
Fumitoshi Ukai1d92d8a2015-08-21 17:10:55 +0900118 glog.V(4).Infof("no concat line:%q", buf)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900119 break
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900120 }
121 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900122 line = bytes.TrimRight(line, "\r\n")
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900123 return line
124}
125
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900126func newAssignAST(p *parser, lhsBytes []byte, rhsBytes []byte, op string) (*assignAST, error) {
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900127 lhs, _, err := parseExpr(lhsBytes, nil, parseOp{alloc: true})
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900128 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900129 return nil, err
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900130 }
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900131 rhs, _, err := parseExpr(rhsBytes, nil, parseOp{alloc: true})
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900132 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900133 return nil, err
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900134 }
135 opt := ""
136 if p != nil {
137 opt = p.defOpt
138 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900139 return &assignAST{
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900140 lhs: lhs,
141 rhs: rhs,
142 op: op,
143 opt: opt,
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900144 }, nil
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900145}
146
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900147func (p *parser) handleDirective(line []byte, directives map[string]directiveFunc) bool {
148 w, data := firstWord(line)
149 if d, ok := directives[string(w)]; ok {
150 d(p, data)
151 return true
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900152 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900153 return false
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900154}
155
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900156func (p *parser) handleRuleOrAssign(line []byte) {
157 rline := line
158 var semi []byte
Fumitoshi Ukai6addc2f2015-07-22 11:33:35 +0900159 if i := findLiteralChar(line, ';', 0, skipVar); i >= 0 {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900160 // preserve after semicolon
161 semi = append(semi, line[i+1:]...)
162 rline = concatline(line[:i])
163 } else {
164 rline = concatline(line)
Shinichiro Hamajide829712015-03-31 18:26:56 +0900165 }
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900166 if p.handleAssign(line) {
167 return
168 }
Fumitoshi Ukai201df422015-07-07 17:31:05 +0900169 // not assignment.
170 // ie. no '=' found or ':' found before '=' (except ':=')
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900171 p.parseMaybeRule(rline, semi)
172 return
173}
174
175func (p *parser) handleAssign(line []byte) bool {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900176 aline, _ := removeComment(concatline(line))
177 aline = trimLeftSpaceBytes(aline)
178 if len(aline) == 0 {
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900179 return false
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900180 }
181 // fmt.Printf("assign: %q=>%q\n", line, aline)
Fumitoshi Ukai6addc2f2015-07-22 11:33:35 +0900182 i := findLiteralChar(aline, ':', '=', skipVar)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900183 if i >= 0 {
184 if aline[i] == '=' {
185 p.parseAssign(aline, i)
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900186 return true
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900187 }
188 if aline[i] == ':' && i+1 < len(aline) && aline[i+1] == '=' {
189 p.parseAssign(aline, i+1)
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900190 return true
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900191 }
192 }
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900193 return false
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900194}
195
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900196func (p *parser) parseAssign(line []byte, sep int) {
197 lhs, op, rhs := line[:sep], line[sep:sep+1], line[sep+1:]
198 if sep > 0 {
199 switch line[sep-1] {
200 case ':', '+', '?':
201 lhs, op = line[:sep-1], line[sep-1:sep+1]
202 }
203 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900204 glog.V(1).Infof("parseAssign %s op:%q opt:%s", line, op, p.defOpt)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900205 lhs = trimSpaceBytes(lhs)
206 rhs = trimLeftSpaceBytes(rhs)
207 aast, err := newAssignAST(p, lhs, rhs, string(op))
208 if err != nil {
209 p.err = err
210 return
211 }
212 aast.srcpos = p.srcpos()
213 p.addStatement(aast)
214}
215
216func (p *parser) parseMaybeRule(line, semi []byte) {
Fumitoshi Ukai56531c12015-07-07 18:04:39 +0900217 if len(line) == 0 {
218 p.err = p.srcpos().errorf("*** missing rule before commands.")
219 return
220 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900221 if line[0] == '\t' {
222 p.err = p.srcpos().errorf("*** commands commence before first target.")
223 return
224 }
Fumitoshi Ukai201df422015-07-07 17:31:05 +0900225 var assign *assignAST
Fumitoshi Ukai6addc2f2015-07-22 11:33:35 +0900226 ci := findLiteralChar(line, ':', 0, skipVar)
Fumitoshi Ukai201df422015-07-07 17:31:05 +0900227 if ci >= 0 {
Fumitoshi Ukai6addc2f2015-07-22 11:33:35 +0900228 eqi := findLiteralChar(line[ci+1:], '=', 0, skipVar)
Fumitoshi Ukai201df422015-07-07 17:31:05 +0900229 if eqi == 0 {
230 panic(fmt.Sprintf("unexpected eq after colon: %q", line))
231 }
232 if eqi > 0 {
233 var lhsbytes []byte
234 op := "="
235 switch line[ci+1+eqi-1] {
236 case ':', '+', '?':
237 lhsbytes = append(lhsbytes, line[ci+1:ci+1+eqi-1]...)
238 op = string(line[ci+1+eqi-1 : ci+1+eqi+1])
239 default:
240 lhsbytes = append(lhsbytes, line[ci+1:ci+1+eqi]...)
241 }
242
243 lhsbytes = trimSpaceBytes(lhsbytes)
244 lhs, _, err := parseExpr(lhsbytes, nil, parseOp{})
245 if err != nil {
246 p.err = p.srcpos().error(err)
247 return
248 }
249 var rhsbytes []byte
250 rhsbytes = append(rhsbytes, line[ci+1+eqi+1:]...)
251 if semi != nil {
252 rhsbytes = append(rhsbytes, ';')
253 rhsbytes = append(rhsbytes, concatline(semi)...)
254 }
255 rhsbytes = trimLeftSpaceBytes(rhsbytes)
256 semi = nil
257 rhs, _, err := parseExpr(rhsbytes, nil, parseOp{})
258 if err != nil {
259 p.err = p.srcpos().error(err)
260 return
261 }
262
263 // TODO(ukai): support override, export in target specific var.
264 assign = &assignAST{
265 lhs: lhs,
266 rhs: rhs,
267 op: op,
268 }
269 assign.srcpos = p.srcpos()
270 line = line[:ci+1]
271 }
272 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900273 expr, _, err := parseExpr(line, nil, parseOp{})
274 if err != nil {
Fumitoshi Ukaicba36c92015-07-07 16:04:18 +0900275 p.err = p.srcpos().error(err)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900276 return
277 }
278 // TODO(ukai): remove ast, and eval here.
279 rast := &maybeRuleAST{
Fumitoshi Ukai201df422015-07-07 17:31:05 +0900280 isRule: ci >= 0,
281 expr: expr,
282 assign: assign,
283 semi: semi,
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900284 }
285 rast.srcpos = p.srcpos()
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900286 glog.V(1).Infof("stmt: %#v", rast)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900287 p.addStatement(rast)
288}
289
290func (p *parser) parseInclude(op string, line []byte) {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900291 // TODO(ukai): parse expr here
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900292 iast := &includeAST{
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900293 expr: string(line),
294 op: op,
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900295 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900296 iast.srcpos = p.srcpos()
297 p.addStatement(iast)
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900298}
299
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900300func (p *parser) parseIfdef(op string, data []byte) {
301 lhs, _, err := parseExpr(data, nil, parseOp{alloc: true})
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900302 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900303 p.err = p.srcpos().error(err)
304 return
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900305 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900306 iast := &ifAST{
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900307 op: op,
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900308 lhs: lhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900309 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900310 iast.srcpos = p.srcpos()
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900311 p.addStatement(iast)
312 p.ifStack = append(p.ifStack, ifState{ast: iast, numNest: p.numIfNest})
313 p.outStmts = &iast.trueStmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900314}
315
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900316func (p *parser) parseTwoQuotes(s []byte) (string, string, []byte, bool) {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900317 var args []string
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900318 for i := 0; i < 2; i++ {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900319 s = trimSpaceBytes(s)
320 if len(s) == 0 {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900321 return "", "", nil, false
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900322 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900323 quote := s[0]
324 if quote != '\'' && quote != '"' {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900325 return "", "", nil, false
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900326 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900327 end := bytes.IndexByte(s[1:], quote) + 1
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900328 if end < 0 {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900329 return "", "", nil, false
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900330 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900331 args = append(args, string(s[1:end]))
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900332 s = s[end+1:]
333 }
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900334 return args[0], args[1], s, true
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900335}
336
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900337// parse
338// "(lhs, rhs)"
339// "lhs, rhs"
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900340func (p *parser) parseEq(s []byte) (string, string, []byte, bool) {
Fumitoshi Ukaia1d68522015-07-07 15:34:22 +0900341 if len(s) == 0 {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900342 return "", "", nil, false
Fumitoshi Ukaia1d68522015-07-07 15:34:22 +0900343 }
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900344 if s[0] == '(' {
345 in := s[1:]
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900346 glog.V(1).Infof("parseEq ( %q )", in)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900347 term := []byte{','}
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900348 v, n, err := parseExpr(in, term, parseOp{matchParen: true})
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900349 if err != nil {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900350 glog.V(1).Infof("parse eq: %q: %v", in, err)
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900351 return "", "", nil, false
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900352 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900353 lhs := v.String()
354 n++
355 n += skipSpaces(in[n:], nil)
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900356 term = []byte{')'}
357 in = in[n:]
358 v, n, err = parseExpr(in, term, parseOp{matchParen: true})
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900359 if err != nil {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900360 glog.V(1).Infof("parse eq 2nd: %q: %v", in, err)
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900361 return "", "", nil, false
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900362 }
363 rhs := v.String()
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900364 in = in[n+1:]
365 in = trimSpaceBytes(in)
366 return lhs, rhs, in, true
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900367 }
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900368 return p.parseTwoQuotes(s)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900369}
370
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900371func (p *parser) parseIfeq(op string, data []byte) {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900372 lhsBytes, rhsBytes, extra, ok := p.parseEq(data)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900373 if !ok {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900374 p.err = p.srcpos().errorf(`*** invalid syntax in conditional.`)
375 return
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900376 }
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900377 if len(extra) > 0 {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900378 glog.V(1).Infof("extra %q", extra)
Fumitoshi Ukaid1578d52015-09-04 17:44:15 +0900379 warnNoPrefix(p.srcpos(), `extraneous text after %q directive`, op)
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900380 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900381
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900382 lhs, _, err := parseExpr([]byte(lhsBytes), nil, parseOp{matchParen: true})
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900383 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900384 p.err = p.srcpos().error(err)
385 return
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900386 }
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900387 rhs, _, err := parseExpr([]byte(rhsBytes), nil, parseOp{matchParen: true})
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900388 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900389 p.err = p.srcpos().error(err)
390 return
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900391 }
392
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900393 iast := &ifAST{
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900394 op: op,
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900395 lhs: lhs,
396 rhs: rhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900397 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900398 iast.srcpos = p.srcpos()
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900399 p.addStatement(iast)
400 p.ifStack = append(p.ifStack, ifState{ast: iast, numNest: p.numIfNest})
401 p.outStmts = &iast.trueStmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900402}
403
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900404func (p *parser) checkIfStack(curKeyword string) error {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900405 if len(p.ifStack) == 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900406 return p.srcpos().errorf(`*** extraneous %q.`, curKeyword)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900407 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900408 return nil
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900409}
410
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900411func (p *parser) parseElse(data []byte) {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900412 err := p.checkIfStack("else")
413 if err != nil {
414 p.err = err
415 return
416 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900417 state := &p.ifStack[len(p.ifStack)-1]
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900418 if state.inElse {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900419 p.err = p.srcpos().errorf(`*** only one "else" per conditional.`)
420 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900421 }
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900422 state.inElse = true
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900423 p.outStmts = &state.ast.falseStmts
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900424
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900425 nextIf := data
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900426 if len(nextIf) == 0 {
427 return
428 }
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900429 var ifDirectives = map[string]directiveFunc{
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900430 "ifdef": ifdefDirective,
431 "ifndef": ifndefDirective,
432 "ifeq": ifeqDirective,
433 "ifneq": ifneqDirective,
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900434 }
435 p.numIfNest = state.numNest + 1
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900436 if p.handleDirective(nextIf, ifDirectives) {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900437 p.numIfNest = 0
438 return
439 }
440 p.numIfNest = 0
Fumitoshi Ukai1ed94372015-07-15 16:28:20 +0900441 warnNoPrefix(p.srcpos(), "extraneous text after `else' directive")
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900442 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900443}
444
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900445func (p *parser) parseEndif(data []byte) {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900446 err := p.checkIfStack("endif")
447 if err != nil {
448 p.err = err
449 return
450 }
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900451 state := p.ifStack[len(p.ifStack)-1]
452 for t := 0; t <= state.numNest; t++ {
453 p.ifStack = p.ifStack[0 : len(p.ifStack)-1]
454 if len(p.ifStack) == 0 {
455 p.outStmts = &p.mk.stmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900456 } else {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900457 state := p.ifStack[len(p.ifStack)-1]
458 if state.inElse {
459 p.outStmts = &state.ast.falseStmts
460 } else {
461 p.outStmts = &state.ast.trueStmts
462 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900463 }
464 }
Fumitoshi Ukai1ed94372015-07-15 16:28:20 +0900465 if len(trimSpaceBytes(data)) > 0 {
466 warnNoPrefix(p.srcpos(), "extraneous text after `endif' directive")
467 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900468 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900469}
470
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900471func (p *parser) parseDefine(data []byte) {
472 p.defineVar = nil
473 p.inDef = nil
474 p.defineVar = append(p.defineVar, trimSpaceBytes(data)...)
475 return
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900476}
477
Fumitoshi Ukai09fcd522015-07-15 14:31:50 +0900478func (p *parser) parseVpath(data []byte) {
479 vline, _ := removeComment(concatline(data))
480 vline = trimLeftSpaceBytes(vline)
481 v, _, err := parseExpr(vline, nil, parseOp{})
482 if err != nil {
483 p.err = p.srcpos().errorf("parse error %q: %v", string(vline), err)
484 return
485 }
486 vast := &vpathAST{
487 expr: v,
488 }
489 vast.srcpos = p.srcpos()
490 p.addStatement(vast)
491}
492
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900493type directiveFunc func(*parser, []byte)
494
495var makeDirectives map[string]directiveFunc
496
497func init() {
498 makeDirectives = map[string]directiveFunc{
499 "include": includeDirective,
500 "-include": sincludeDirective,
501 "sinclude": sincludeDirective,
502 "ifdef": ifdefDirective,
503 "ifndef": ifndefDirective,
504 "ifeq": ifeqDirective,
505 "ifneq": ifneqDirective,
506 "else": elseDirective,
507 "endif": endifDirective,
508 "define": defineDirective,
509 "override": overrideDirective,
510 "export": exportDirective,
511 "unexport": unexportDirective,
Fumitoshi Ukai09fcd522015-07-15 14:31:50 +0900512 "vpath": vpathDirective,
Shinichiro Hamajie103f652015-04-11 19:49:51 +0900513 }
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900514}
515
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900516func includeDirective(p *parser, data []byte) {
517 p.parseInclude("include", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900518}
519
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900520func sincludeDirective(p *parser, data []byte) {
521 p.parseInclude("-include", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900522}
523
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900524func ifdefDirective(p *parser, data []byte) {
525 p.parseIfdef("ifdef", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900526}
527
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900528func ifndefDirective(p *parser, data []byte) {
529 p.parseIfdef("ifndef", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900530}
531
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900532func ifeqDirective(p *parser, data []byte) {
533 p.parseIfeq("ifeq", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900534}
535
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900536func ifneqDirective(p *parser, data []byte) {
537 p.parseIfeq("ifneq", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900538}
539
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900540func elseDirective(p *parser, data []byte) {
541 p.parseElse(data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900542}
543
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900544func endifDirective(p *parser, data []byte) {
545 p.parseEndif(data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900546}
547
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900548func defineDirective(p *parser, data []byte) {
549 p.parseDefine(data)
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900550}
551
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900552func overrideDirective(p *parser, data []byte) {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900553 p.defOpt = "override"
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900554 defineDirective := map[string]directiveFunc{
555 "define": defineDirective,
556 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900557 glog.V(1).Infof("override define? %q", data)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900558 if p.handleDirective(data, defineDirective) {
559 return
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900560 }
561 // e.g. overrider foo := bar
562 // line will be "foo := bar".
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900563 if p.handleAssign(data) {
564 return
565 }
566 p.defOpt = ""
567 var line []byte
568 line = append(line, []byte("override ")...)
569 line = append(line, data...)
570 p.handleRuleOrAssign(line)
Fumitoshi Ukaif5b916d2015-07-15 15:57:19 +0900571 // TODO(ukai): evaluate now to detect invalid "override" directive here?
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900572}
573
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900574func handleExport(p *parser, data []byte, export bool) (hasEqual bool) {
575 i := bytes.IndexByte(data, '=')
576 if i > 0 {
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900577 hasEqual = true
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900578 switch data[i-1] {
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900579 case ':', '+', '?':
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900580 i--
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900581 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900582 data = data[:i]
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900583 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900584 east := &exportAST{
Fumitoshi Ukaif5b916d2015-07-15 15:57:19 +0900585 expr: data,
586 hasEqual: hasEqual,
587 export: export,
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900588 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900589 east.srcpos = p.srcpos()
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900590 glog.V(1).Infof("export %v", east)
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900591 p.addStatement(east)
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900592 return hasEqual
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900593}
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900594
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900595func exportDirective(p *parser, data []byte) {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900596 p.defOpt = "export"
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900597 defineDirective := map[string]directiveFunc{
598 "define": defineDirective,
599 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900600 glog.V(1).Infof("export define? %q", data)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900601 if p.handleDirective(data, defineDirective) {
602 return
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900603 }
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900604
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900605 if !handleExport(p, data, true) {
606 return
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900607 }
608
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900609 // e.g. export foo := bar
610 // line will be "foo := bar".
Fumitoshi Ukaibcb3b4b2015-07-07 18:00:13 +0900611 p.handleAssign(data)
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900612}
613
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900614func unexportDirective(p *parser, data []byte) {
615 handleExport(p, data, false)
616 return
Shinichiro Hamajica668572015-06-17 06:36:45 +0900617}
618
Fumitoshi Ukai09fcd522015-07-15 14:31:50 +0900619func vpathDirective(p *parser, data []byte) {
620 p.parseVpath(data)
621}
622
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900623func (p *parser) parse() (mk makefile, err error) {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900624 for !p.done {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900625 line := p.readLine()
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900626 if glog.V(1) {
627 glog.Infof("%s: %q", p.srcpos(), line)
Fumitoshi Ukai2a2deb32015-07-08 11:46:14 +0900628 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900629 if p.defineVar != nil {
630 p.processDefine(line)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900631 if p.err != nil {
632 return makefile{}, p.err
633 }
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900634 continue
635 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900636 p.defOpt = ""
637 if p.inRecipe {
638 if len(line) > 0 && line[0] == '\t' {
639 cast := &commandAST{cmd: string(line[1:])}
640 cast.srcpos = p.srcpos()
641 p.addStatement(cast)
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900642 continue
643 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900644 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900645 p.parseLine(line)
646 if p.err != nil {
647 return makefile{}, p.err
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900648 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900649 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900650 return p.mk, p.err
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900651}
652
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900653func (p *parser) parseLine(line []byte) {
654 cline := concatline(line)
655 if len(cline) == 0 {
656 return
657 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900658 if glog.V(1) {
659 glog.Infof("concatline:%q", cline)
Fumitoshi Ukai2a2deb32015-07-08 11:46:14 +0900660 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900661 var dline []byte
662 cline, _ = removeComment(cline)
663 dline = append(dline, cline...)
664 dline = trimSpaceBytes(dline)
665 if len(dline) == 0 {
666 return
667 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900668 if glog.V(1) {
669 glog.Infof("directive?: %q", dline)
Fumitoshi Ukai2a2deb32015-07-08 11:46:14 +0900670 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900671 if p.handleDirective(dline, makeDirectives) {
672 return
673 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900674 if glog.V(1) {
675 glog.Infof("rule or assign?: %q", line)
Fumitoshi Ukai2a2deb32015-07-08 11:46:14 +0900676 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900677 p.handleRuleOrAssign(line)
678}
679
680func (p *parser) processDefine(line []byte) {
Fumitoshi Ukai1d92d8a2015-08-21 17:10:55 +0900681 line = append(line, '\n')
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900682 line = concatline(line)
Fumitoshi Ukai1d92d8a2015-08-21 17:10:55 +0900683 if line[len(line)-1] != '\n' {
684 line = append(line, '\n')
685 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900686 if glog.V(1) {
687 glog.Infof("concatline:%q", line)
Fumitoshi Ukai2a2deb32015-07-08 11:46:14 +0900688 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900689 if !p.isEndef(line) {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900690 p.inDef = append(p.inDef, line...)
Fumitoshi Ukai1d2c92d2015-07-07 12:10:20 +0900691 if p.inDef == nil {
692 p.inDef = []byte{}
693 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900694 return
695 }
Fumitoshi Ukai1d92d8a2015-08-21 17:10:55 +0900696 if p.inDef[len(p.inDef)-1] == '\n' {
697 p.inDef = p.inDef[:len(p.inDef)-1]
698 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900699 glog.V(1).Infof("multilineAssign %q %q", p.defineVar, p.inDef)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900700 aast, err := newAssignAST(p, p.defineVar, p.inDef, "=")
701 if err != nil {
702 p.err = p.srcpos().errorf("assign error %q=%q: %v", p.defineVar, p.inDef, err)
703 return
704 }
705 aast.srcpos = p.srcpos()
706 aast.srcpos.lineno -= bytes.Count(p.inDef, []byte{'\n'})
707 p.addStatement(aast)
708 p.defineVar = nil
709 p.inDef = nil
710 return
711}
712
713func (p *parser) isEndef(line []byte) bool {
714 if bytes.Equal(line, []byte("endef")) {
715 return true
716 }
717 w, data := firstWord(line)
718 if bytes.Equal(w, []byte("endef")) {
719 data, _ = removeComment(data)
720 data = trimLeftSpaceBytes(data)
721 if len(data) > 0 {
722 warnNoPrefix(p.srcpos(), `extraneous text after "endef" directive`)
723 }
724 return true
725 }
726 return false
727}
728
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900729func defaultMakefile() (string, error) {
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900730 candidates := []string{"GNUmakefile", "makefile", "Makefile"}
731 for _, filename := range candidates {
732 if exists(filename) {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900733 return filename, nil
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900734 }
735 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900736 return "", errors.New("no targets specified and no makefile found")
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900737}
738
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900739func parseMakefileReader(rd io.Reader, loc srcpos) (makefile, error) {
740 parser := newParser(rd, loc.filename)
741 parser.lineno = loc.lineno
742 parser.elineno = loc.lineno
Shinichiro Hamaji370be722015-04-10 14:55:23 +0900743 parser.linenoFixed = true
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900744 return parser.parse()
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900745}
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900746
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900747func parseMakefileString(s string, loc srcpos) (makefile, error) {
748 return parseMakefileReader(strings.NewReader(s), loc)
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900749}
750
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900751func parseMakefileBytes(s []byte, loc srcpos) (makefile, error) {
752 return parseMakefileReader(bytes.NewReader(s), loc)
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900753}
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900754
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900755type mkCacheEntry struct {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900756 mk makefile
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900757 hash [sha1.Size]byte
758 err error
759 ts int64
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900760}
761
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900762type makefileCacheT struct {
763 mu sync.Mutex
764 mk map[string]mkCacheEntry
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900765}
766
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900767var makefileCache = &makefileCacheT{
768 mk: make(map[string]mkCacheEntry),
769}
770
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900771func (mc *makefileCacheT) lookup(filename string) (makefile, [sha1.Size]byte, bool, error) {
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900772 var hash [sha1.Size]byte
773 mc.mu.Lock()
774 c, present := mc.mk[filename]
775 mc.mu.Unlock()
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900776 if !present {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900777 return makefile{}, hash, false, nil
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900778 }
779 ts := getTimestamp(filename)
780 if ts < 0 || ts >= c.ts {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900781 return makefile{}, hash, false, nil
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900782 }
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900783 return c.mk, c.hash, true, c.err
784}
785
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900786func (mc *makefileCacheT) parse(filename string) (makefile, [sha1.Size]byte, error) {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900787 glog.Infof("parse Makefile %q", filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900788 mk, hash, ok, err := makefileCache.lookup(filename)
789 if ok {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900790 if glog.V(1) {
791 glog.Infof("makefile cache hit for %q", filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900792 }
793 return mk, hash, err
794 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900795 if glog.V(1) {
796 glog.Infof("reading makefile %q", filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900797 }
798 c, err := ioutil.ReadFile(filename)
799 if err != nil {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900800 return makefile{}, hash, err
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900801 }
802 hash = sha1.Sum(c)
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900803 mk, err = parseMakefile(c, filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900804 if err != nil {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900805 return makefile{}, hash, err
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900806 }
807 makefileCache.mu.Lock()
808 makefileCache.mk[filename] = mkCacheEntry{
809 mk: mk,
810 hash: hash,
811 err: err,
812 ts: time.Now().Unix(),
813 }
814 makefileCache.mu.Unlock()
815 return mk, hash, err
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900816}
817
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900818func parseMakefile(s []byte, filename string) (makefile, error) {
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900819 parser := newParser(bytes.NewReader(s), filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900820 return parser.parse()
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900821}