blob: d5f5a4106328fbd96e110e3f3addb014e81222b6 [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
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090054 inRecipe bool
Shinichiro Hamaji370be722015-04-10 14:55:23 +090055 ifStack []ifState
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090056
57 defineVar []byte
58 inDef []byte
59
60 defOpt string
61 numIfNest int
62 err error
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090063}
64
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +090065func newParser(rd io.Reader, filename string) *parser {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090066 p := &parser{
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +090067 rd: bufio.NewReader(rd),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090068 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090069 p.mk.filename = filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090070 p.outStmts = &p.mk.stmts
71 return p
72}
73
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090074func (p *parser) srcpos() srcpos {
75 return srcpos{
76 filename: p.mk.filename,
77 lineno: p.lineno,
78 }
79}
80
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +090081func (p *parser) addStatement(stmt ast) {
82 *p.outStmts = append(*p.outStmts, stmt)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090083 switch stmt.(type) {
84 case *maybeRuleAST:
85 p.inRecipe = true
86 case *assignAST, *includeAST, *exportAST:
87 p.inRecipe = false
88 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090089}
90
Shinichiro Hamajie1841582015-03-30 17:20:33 +090091func (p *parser) readLine() []byte {
Shinichiro Hamaji370be722015-04-10 14:55:23 +090092 if !p.linenoFixed {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090093 p.lineno = p.elineno + 1
Shinichiro Hamaji370be722015-04-10 14:55:23 +090094 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +090095 var line []byte
96 for !p.done {
97 buf, err := p.rd.ReadBytes('\n')
98 if !p.linenoFixed {
99 p.elineno++
100 }
101 if err == io.EOF {
102 p.done = true
103 } else if err != nil {
104 p.err = fmt.Errorf("readline %s: %v", p.srcpos(), err)
105 p.done = true
106 }
107 line = append(line, buf...)
108 buf = bytes.TrimRight(buf, "\r\n")
109 backslash := false
110 for len(buf) > 1 && buf[len(buf)-1] == '\\' {
111 buf = buf[:len(buf)-1]
112 backslash = !backslash
113 }
114 if !backslash {
115 break
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900116 }
117 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900118 line = bytes.TrimRight(line, "\r\n")
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900119 return line
120}
121
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900122func newAssignAST(p *parser, lhsBytes []byte, rhsBytes []byte, op string) (*assignAST, error) {
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900123 lhs, _, err := parseExpr(lhsBytes, nil, parseOp{alloc: true})
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900124 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900125 return nil, err
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900126 }
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900127 rhs, _, err := parseExpr(rhsBytes, 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 }
131 opt := ""
132 if p != nil {
133 opt = p.defOpt
134 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900135 return &assignAST{
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900136 lhs: lhs,
137 rhs: rhs,
138 op: op,
139 opt: opt,
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900140 }, nil
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900141}
142
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900143func (p *parser) handleDirective(line []byte, directives map[string]directiveFunc) bool {
144 w, data := firstWord(line)
145 if d, ok := directives[string(w)]; ok {
146 d(p, data)
147 return true
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900148 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900149 return false
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900150}
151
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900152func (p *parser) handleRuleOrAssign(line []byte) {
153 rline := line
154 var semi []byte
155 if i := findLiteralChar(line, []byte{';'}, true); i >= 0 {
156 // preserve after semicolon
157 semi = append(semi, line[i+1:]...)
158 rline = concatline(line[:i])
159 } else {
160 rline = concatline(line)
Shinichiro Hamajide829712015-03-31 18:26:56 +0900161 }
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900162 if p.handleAssign(line) {
163 return
164 }
Fumitoshi Ukai201df422015-07-07 17:31:05 +0900165 // not assignment.
166 // ie. no '=' found or ':' found before '=' (except ':=')
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900167 p.parseMaybeRule(rline, semi)
168 return
169}
170
171func (p *parser) handleAssign(line []byte) bool {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900172 aline, _ := removeComment(concatline(line))
173 aline = trimLeftSpaceBytes(aline)
174 if len(aline) == 0 {
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900175 return false
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900176 }
177 // fmt.Printf("assign: %q=>%q\n", line, aline)
178 i := findLiteralChar(aline, []byte{':', '='}, true)
179 if i >= 0 {
180 if aline[i] == '=' {
181 p.parseAssign(aline, i)
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900182 return true
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900183 }
184 if aline[i] == ':' && i+1 < len(aline) && aline[i+1] == '=' {
185 p.parseAssign(aline, i+1)
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900186 return true
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900187 }
188 }
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900189 return false
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900190}
191
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900192func (p *parser) parseAssign(line []byte, sep int) {
193 lhs, op, rhs := line[:sep], line[sep:sep+1], line[sep+1:]
194 if sep > 0 {
195 switch line[sep-1] {
196 case ':', '+', '?':
197 lhs, op = line[:sep-1], line[sep-1:sep+1]
198 }
199 }
Fumitoshi Ukaibcb3b4b2015-07-07 18:00:13 +0900200 logf("parseAssign %s op:%s opt:%s", line, op, p.defOpt)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900201 lhs = trimSpaceBytes(lhs)
202 rhs = trimLeftSpaceBytes(rhs)
203 aast, err := newAssignAST(p, lhs, rhs, string(op))
204 if err != nil {
205 p.err = err
206 return
207 }
208 aast.srcpos = p.srcpos()
209 p.addStatement(aast)
210}
211
212func (p *parser) parseMaybeRule(line, semi []byte) {
Fumitoshi Ukai56531c12015-07-07 18:04:39 +0900213 if len(line) == 0 {
214 p.err = p.srcpos().errorf("*** missing rule before commands.")
215 return
216 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900217 if line[0] == '\t' {
218 p.err = p.srcpos().errorf("*** commands commence before first target.")
219 return
220 }
Fumitoshi Ukai201df422015-07-07 17:31:05 +0900221 var assign *assignAST
222 ci := findLiteralChar(line, []byte{':'}, true)
223 if ci >= 0 {
224 eqi := findLiteralChar(line[ci+1:], []byte{'='}, true)
225 if eqi == 0 {
226 panic(fmt.Sprintf("unexpected eq after colon: %q", line))
227 }
228 if eqi > 0 {
229 var lhsbytes []byte
230 op := "="
231 switch line[ci+1+eqi-1] {
232 case ':', '+', '?':
233 lhsbytes = append(lhsbytes, line[ci+1:ci+1+eqi-1]...)
234 op = string(line[ci+1+eqi-1 : ci+1+eqi+1])
235 default:
236 lhsbytes = append(lhsbytes, line[ci+1:ci+1+eqi]...)
237 }
238
239 lhsbytes = trimSpaceBytes(lhsbytes)
240 lhs, _, err := parseExpr(lhsbytes, nil, parseOp{})
241 if err != nil {
242 p.err = p.srcpos().error(err)
243 return
244 }
245 var rhsbytes []byte
246 rhsbytes = append(rhsbytes, line[ci+1+eqi+1:]...)
247 if semi != nil {
248 rhsbytes = append(rhsbytes, ';')
249 rhsbytes = append(rhsbytes, concatline(semi)...)
250 }
251 rhsbytes = trimLeftSpaceBytes(rhsbytes)
252 semi = nil
253 rhs, _, err := parseExpr(rhsbytes, nil, parseOp{})
254 if err != nil {
255 p.err = p.srcpos().error(err)
256 return
257 }
258
259 // TODO(ukai): support override, export in target specific var.
260 assign = &assignAST{
261 lhs: lhs,
262 rhs: rhs,
263 op: op,
264 }
265 assign.srcpos = p.srcpos()
266 line = line[:ci+1]
267 }
268 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900269 expr, _, err := parseExpr(line, nil, parseOp{})
270 if err != nil {
Fumitoshi Ukaicba36c92015-07-07 16:04:18 +0900271 p.err = p.srcpos().error(err)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900272 return
273 }
274 // TODO(ukai): remove ast, and eval here.
275 rast := &maybeRuleAST{
Fumitoshi Ukai201df422015-07-07 17:31:05 +0900276 isRule: ci >= 0,
277 expr: expr,
278 assign: assign,
279 semi: semi,
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900280 }
281 rast.srcpos = p.srcpos()
Fumitoshi Ukai201df422015-07-07 17:31:05 +0900282 logf("stmt: %#v", rast)
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900283 p.addStatement(rast)
284}
285
286func (p *parser) parseInclude(op string, line []byte) {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900287 // TODO(ukai): parse expr here
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900288 iast := &includeAST{
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900289 expr: string(line),
290 op: op,
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900291 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900292 iast.srcpos = p.srcpos()
293 p.addStatement(iast)
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900294}
295
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900296func (p *parser) parseIfdef(op string, data []byte) {
297 lhs, _, err := parseExpr(data, nil, parseOp{alloc: true})
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900298 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900299 p.err = p.srcpos().error(err)
300 return
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900301 }
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900302 iast := &ifAST{
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900303 op: op,
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900304 lhs: lhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900305 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900306 iast.srcpos = p.srcpos()
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900307 p.addStatement(iast)
308 p.ifStack = append(p.ifStack, ifState{ast: iast, numNest: p.numIfNest})
309 p.outStmts = &iast.trueStmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900310}
311
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900312func (p *parser) parseTwoQuotes(s []byte) (string, string, []byte, bool) {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900313 var args []string
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900314 for i := 0; i < 2; i++ {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900315 s = trimSpaceBytes(s)
316 if len(s) == 0 {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900317 return "", "", nil, false
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900318 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900319 quote := s[0]
320 if quote != '\'' && quote != '"' {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900321 return "", "", nil, false
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900322 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900323 end := bytes.IndexByte(s[1:], quote) + 1
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900324 if end < 0 {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900325 return "", "", nil, false
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900326 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900327 args = append(args, string(s[1:end]))
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900328 s = s[end+1:]
329 }
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900330 return args[0], args[1], s, true
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900331}
332
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900333// parse
334// "(lhs, rhs)"
335// "lhs, rhs"
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900336func (p *parser) parseEq(s []byte) (string, string, []byte, bool) {
Fumitoshi Ukaia1d68522015-07-07 15:34:22 +0900337 if len(s) == 0 {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900338 return "", "", nil, false
Fumitoshi Ukaia1d68522015-07-07 15:34:22 +0900339 }
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900340 if s[0] == '(' {
341 in := s[1:]
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900342 logf("parseEq ( %q )", in)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900343 term := []byte{','}
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900344 v, n, err := parseExpr(in, term, parseOp{matchParen: true})
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900345 if err != nil {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900346 logf("parse eq: %q: %v", in, err)
347 return "", "", nil, false
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900348 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900349 lhs := v.String()
350 n++
351 n += skipSpaces(in[n:], nil)
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900352 term = []byte{')'}
353 in = in[n:]
354 v, n, err = parseExpr(in, term, parseOp{matchParen: true})
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900355 if err != nil {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900356 logf("parse eq 2nd: %q: %v", in, err)
357 return "", "", nil, false
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900358 }
359 rhs := v.String()
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900360 in = in[n+1:]
361 in = trimSpaceBytes(in)
362 return lhs, rhs, in, true
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900363 }
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900364 return p.parseTwoQuotes(s)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900365}
366
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900367func (p *parser) parseIfeq(op string, data []byte) {
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900368 lhsBytes, rhsBytes, extra, ok := p.parseEq(data)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900369 if !ok {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900370 p.err = p.srcpos().errorf(`*** invalid syntax in conditional.`)
371 return
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900372 }
Fumitoshi Ukaifc02d672015-07-07 15:49:58 +0900373 if len(extra) > 0 {
374 logf("extra %q", extra)
375 p.err = p.srcpos().errorf(`extraneous text after %q directive`, op)
376 return
377 }
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900378
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900379 lhs, _, err := parseExpr([]byte(lhsBytes), nil, parseOp{matchParen: true})
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900380 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900381 p.err = p.srcpos().error(err)
382 return
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900383 }
Fumitoshi Ukaie9aa3802015-07-03 11:33:23 +0900384 rhs, _, err := parseExpr([]byte(rhsBytes), nil, parseOp{matchParen: true})
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900385 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900386 p.err = p.srcpos().error(err)
387 return
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900388 }
389
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900390 iast := &ifAST{
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900391 op: op,
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900392 lhs: lhs,
393 rhs: rhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900394 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900395 iast.srcpos = p.srcpos()
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900396 p.addStatement(iast)
397 p.ifStack = append(p.ifStack, ifState{ast: iast, numNest: p.numIfNest})
398 p.outStmts = &iast.trueStmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900399}
400
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900401func (p *parser) checkIfStack(curKeyword string) error {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900402 if len(p.ifStack) == 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900403 return p.srcpos().errorf(`*** extraneous %q.`, curKeyword)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900404 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900405 return nil
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900406}
407
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900408func (p *parser) parseElse(data []byte) {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900409 err := p.checkIfStack("else")
410 if err != nil {
411 p.err = err
412 return
413 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900414 state := &p.ifStack[len(p.ifStack)-1]
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900415 if state.inElse {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900416 p.err = p.srcpos().errorf(`*** only one "else" per conditional.`)
417 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900418 }
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900419 state.inElse = true
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900420 p.outStmts = &state.ast.falseStmts
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900421
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900422 nextIf := data
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900423 if len(nextIf) == 0 {
424 return
425 }
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900426 var ifDirectives = map[string]directiveFunc{
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900427 "ifdef": ifdefDirective,
428 "ifndef": ifndefDirective,
429 "ifeq": ifeqDirective,
430 "ifneq": ifneqDirective,
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900431 }
432 p.numIfNest = state.numNest + 1
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900433 if p.handleDirective(nextIf, ifDirectives) {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900434 p.numIfNest = 0
435 return
436 }
437 p.numIfNest = 0
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900438 warnNoPrefix(p.srcpos(), "extraneous text after `else` directive")
439 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900440}
441
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900442func (p *parser) parseEndif(data []byte) {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900443 err := p.checkIfStack("endif")
444 if err != nil {
445 p.err = err
446 return
447 }
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900448 state := p.ifStack[len(p.ifStack)-1]
449 for t := 0; t <= state.numNest; t++ {
450 p.ifStack = p.ifStack[0 : len(p.ifStack)-1]
451 if len(p.ifStack) == 0 {
452 p.outStmts = &p.mk.stmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900453 } else {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900454 state := p.ifStack[len(p.ifStack)-1]
455 if state.inElse {
456 p.outStmts = &state.ast.falseStmts
457 } else {
458 p.outStmts = &state.ast.trueStmts
459 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900460 }
461 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900462 return
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900463}
464
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900465func (p *parser) parseDefine(data []byte) {
466 p.defineVar = nil
467 p.inDef = nil
468 p.defineVar = append(p.defineVar, trimSpaceBytes(data)...)
469 return
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900470}
471
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900472type directiveFunc func(*parser, []byte)
473
474var makeDirectives map[string]directiveFunc
475
476func init() {
477 makeDirectives = map[string]directiveFunc{
478 "include": includeDirective,
479 "-include": sincludeDirective,
480 "sinclude": sincludeDirective,
481 "ifdef": ifdefDirective,
482 "ifndef": ifndefDirective,
483 "ifeq": ifeqDirective,
484 "ifneq": ifneqDirective,
485 "else": elseDirective,
486 "endif": endifDirective,
487 "define": defineDirective,
488 "override": overrideDirective,
489 "export": exportDirective,
490 "unexport": unexportDirective,
Shinichiro Hamajie103f652015-04-11 19:49:51 +0900491 }
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900492}
493
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900494func includeDirective(p *parser, data []byte) {
495 p.parseInclude("include", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900496}
497
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900498func sincludeDirective(p *parser, data []byte) {
499 p.parseInclude("-include", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900500}
501
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900502func ifdefDirective(p *parser, data []byte) {
503 p.parseIfdef("ifdef", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900504}
505
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900506func ifndefDirective(p *parser, data []byte) {
507 p.parseIfdef("ifndef", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900508}
509
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900510func ifeqDirective(p *parser, data []byte) {
511 p.parseIfeq("ifeq", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900512}
513
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900514func ifneqDirective(p *parser, data []byte) {
515 p.parseIfeq("ifneq", data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900516}
517
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900518func elseDirective(p *parser, data []byte) {
519 p.parseElse(data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900520}
521
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900522func endifDirective(p *parser, data []byte) {
523 p.parseEndif(data)
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900524}
525
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900526func defineDirective(p *parser, data []byte) {
527 p.parseDefine(data)
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900528}
529
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900530func overrideDirective(p *parser, data []byte) {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900531 p.defOpt = "override"
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900532 defineDirective := map[string]directiveFunc{
533 "define": defineDirective,
534 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900535 logf("override define? %q", data)
536 if p.handleDirective(data, defineDirective) {
537 return
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900538 }
539 // e.g. overrider foo := bar
540 // line will be "foo := bar".
Fumitoshi Ukai4cb507f2015-07-07 11:46:58 +0900541 if p.handleAssign(data) {
542 return
543 }
544 p.defOpt = ""
545 var line []byte
546 line = append(line, []byte("override ")...)
547 line = append(line, data...)
548 p.handleRuleOrAssign(line)
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900549}
550
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900551func handleExport(p *parser, data []byte, export bool) (hasEqual bool) {
552 i := bytes.IndexByte(data, '=')
553 if i > 0 {
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900554 hasEqual = true
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900555 switch data[i-1] {
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900556 case ':', '+', '?':
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900557 i--
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900558 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900559 data = data[:i]
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900560 }
561
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900562 east := &exportAST{
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900563 expr: data,
Shinichiro Hamajif61033d2015-05-29 15:01:48 +0900564 export: export,
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900565 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900566 east.srcpos = p.srcpos()
Fumitoshi Ukaibcb3b4b2015-07-07 18:00:13 +0900567 logf("export %v", east)
Fumitoshi Ukai91ed5d72015-06-25 13:08:09 +0900568 p.addStatement(east)
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900569 return hasEqual
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900570}
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900571
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900572func exportDirective(p *parser, data []byte) {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900573 p.defOpt = "export"
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900574 defineDirective := map[string]directiveFunc{
575 "define": defineDirective,
576 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900577 logf("export define? %q", data)
578 if p.handleDirective(data, defineDirective) {
579 return
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900580 }
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900581
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900582 if !handleExport(p, data, true) {
583 return
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900584 }
585
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900586 // e.g. export foo := bar
587 // line will be "foo := bar".
Fumitoshi Ukaibcb3b4b2015-07-07 18:00:13 +0900588 p.handleAssign(data)
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900589}
590
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900591func unexportDirective(p *parser, data []byte) {
592 handleExport(p, data, false)
593 return
Shinichiro Hamajica668572015-06-17 06:36:45 +0900594}
595
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900596func (p *parser) parse() (mk makefile, err error) {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900597 for !p.done {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900598 line := p.readLine()
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900599 logf("line: %q", line)
600 if p.defineVar != nil {
601 p.processDefine(line)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900602 if p.err != nil {
603 return makefile{}, p.err
604 }
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900605 continue
606 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900607 p.defOpt = ""
608 if p.inRecipe {
609 if len(line) > 0 && line[0] == '\t' {
610 cast := &commandAST{cmd: string(line[1:])}
611 cast.srcpos = p.srcpos()
612 p.addStatement(cast)
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900613 continue
614 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900615 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900616 p.parseLine(line)
617 if p.err != nil {
618 return makefile{}, p.err
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900619 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900620 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900621 return p.mk, p.err
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900622}
623
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900624func (p *parser) parseLine(line []byte) {
625 cline := concatline(line)
626 if len(cline) == 0 {
627 return
628 }
629 logf("concatline:%q", cline)
630 var dline []byte
631 cline, _ = removeComment(cline)
632 dline = append(dline, cline...)
633 dline = trimSpaceBytes(dline)
634 if len(dline) == 0 {
635 return
636 }
637 logf("directive?: %q", dline)
638 if p.handleDirective(dline, makeDirectives) {
639 return
640 }
641 logf("rule or assign?: %q", line)
642 p.handleRuleOrAssign(line)
643}
644
645func (p *parser) processDefine(line []byte) {
646 line = concatline(line)
647 logf("concatline:%q", line)
648 if !p.isEndef(line) {
Fumitoshi Ukai1d2c92d2015-07-07 12:10:20 +0900649 if p.inDef != nil {
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900650 p.inDef = append(p.inDef, '\n')
651 }
652 p.inDef = append(p.inDef, line...)
Fumitoshi Ukai1d2c92d2015-07-07 12:10:20 +0900653 if p.inDef == nil {
654 p.inDef = []byte{}
655 }
Fumitoshi Ukaib97be672015-07-02 15:12:48 +0900656 return
657 }
658 logf("multilineAssign %q %q", p.defineVar, p.inDef)
659 aast, err := newAssignAST(p, p.defineVar, p.inDef, "=")
660 if err != nil {
661 p.err = p.srcpos().errorf("assign error %q=%q: %v", p.defineVar, p.inDef, err)
662 return
663 }
664 aast.srcpos = p.srcpos()
665 aast.srcpos.lineno -= bytes.Count(p.inDef, []byte{'\n'})
666 p.addStatement(aast)
667 p.defineVar = nil
668 p.inDef = nil
669 return
670}
671
672func (p *parser) isEndef(line []byte) bool {
673 if bytes.Equal(line, []byte("endef")) {
674 return true
675 }
676 w, data := firstWord(line)
677 if bytes.Equal(w, []byte("endef")) {
678 data, _ = removeComment(data)
679 data = trimLeftSpaceBytes(data)
680 if len(data) > 0 {
681 warnNoPrefix(p.srcpos(), `extraneous text after "endef" directive`)
682 }
683 return true
684 }
685 return false
686}
687
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900688func defaultMakefile() (string, error) {
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900689 candidates := []string{"GNUmakefile", "makefile", "Makefile"}
690 for _, filename := range candidates {
691 if exists(filename) {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900692 return filename, nil
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900693 }
694 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900695 return "", errors.New("no targets specified and no makefile found")
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900696}
697
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900698func parseMakefileReader(rd io.Reader, loc srcpos) (makefile, error) {
699 parser := newParser(rd, loc.filename)
700 parser.lineno = loc.lineno
701 parser.elineno = loc.lineno
Shinichiro Hamaji370be722015-04-10 14:55:23 +0900702 parser.linenoFixed = true
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900703 return parser.parse()
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900704}
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900705
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900706func parseMakefileString(s string, loc srcpos) (makefile, error) {
707 return parseMakefileReader(strings.NewReader(s), loc)
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900708}
709
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900710func parseMakefileBytes(s []byte, loc srcpos) (makefile, error) {
711 return parseMakefileReader(bytes.NewReader(s), loc)
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900712}
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900713
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900714type mkCacheEntry struct {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900715 mk makefile
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900716 hash [sha1.Size]byte
717 err error
718 ts int64
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900719}
720
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900721type makefileCacheT struct {
722 mu sync.Mutex
723 mk map[string]mkCacheEntry
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900724}
725
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900726var makefileCache = &makefileCacheT{
727 mk: make(map[string]mkCacheEntry),
728}
729
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900730func (mc *makefileCacheT) lookup(filename string) (makefile, [sha1.Size]byte, bool, error) {
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900731 var hash [sha1.Size]byte
732 mc.mu.Lock()
733 c, present := mc.mk[filename]
734 mc.mu.Unlock()
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900735 if !present {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900736 return makefile{}, hash, false, nil
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900737 }
738 ts := getTimestamp(filename)
739 if ts < 0 || ts >= c.ts {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900740 return makefile{}, hash, false, nil
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900741 }
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900742 return c.mk, c.hash, true, c.err
743}
744
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900745func (mc *makefileCacheT) parse(filename string) (makefile, [sha1.Size]byte, error) {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900746 logf("parse Makefile %q", filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900747 mk, hash, ok, err := makefileCache.lookup(filename)
748 if ok {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900749 if LogFlag {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900750 logf("makefile cache hit for %q", filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900751 }
752 return mk, hash, err
753 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900754 if LogFlag {
Fumitoshi Ukai07cf1212015-06-25 17:16:25 +0900755 logf("reading makefile %q", filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900756 }
757 c, err := ioutil.ReadFile(filename)
758 if err != nil {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900759 return makefile{}, hash, err
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900760 }
761 hash = sha1.Sum(c)
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900762 mk, err = parseMakefile(c, filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900763 if err != nil {
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900764 return makefile{}, hash, err
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900765 }
766 makefileCache.mu.Lock()
767 makefileCache.mk[filename] = mkCacheEntry{
768 mk: mk,
769 hash: hash,
770 err: err,
771 ts: time.Now().Unix(),
772 }
773 makefileCache.mu.Unlock()
774 return mk, hash, err
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900775}
776
Fumitoshi Ukai08eda652015-06-25 16:27:10 +0900777func parseMakefile(s []byte, filename string) (makefile, error) {
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900778 parser := newParser(bytes.NewReader(s), filename)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900779 return parser.parse()
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900780}