blob: 950ca5590c9ba8c2543c611e4c4b391f5623301d [file] [log] [blame]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09001package main
2
Fumitoshi Ukai0aa4fc42015-04-10 17:00:19 +09003//go:generate go run testcase/gen_testcase_parse_benchmark.go
4//
5// $ go generate
6// $ go test -bench .
7
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09008import (
9 "bufio"
Shinichiro Hamajie1841582015-03-30 17:20:33 +090010 "bytes"
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +090011 "fmt"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090012 "io"
13 "os"
Shinichiro Hamajid7bef602015-03-30 19:55:32 +090014 "strings"
Shinichiro Hamaji584bb062015-06-04 13:25:13 +090015 "time"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090016)
17
18type Makefile struct {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090019 filename string
20 stmts []AST
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090021}
22
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090023type ifState struct {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +090024 ast *IfAST
25 inElse bool
26 numNest int
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090027}
28
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090029type parser struct {
Shinichiro Hamaji370be722015-04-10 14:55:23 +090030 rd *bufio.Reader
31 mk Makefile
32 lineno int
33 elineno int // lineno == elineno unless there is trailing '\'.
34 linenoFixed bool
35 unBuf []byte
36 hasUnBuf bool
37 done bool
38 outStmts *[]AST
39 ifStack []ifState
40 inDef []string
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +090041 defOpt string
Shinichiro Hamaji370be722015-04-10 14:55:23 +090042 numIfNest int
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090043}
44
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +090045func newParser(rd io.Reader, filename string) *parser {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090046 p := &parser{
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +090047 rd: bufio.NewReader(rd),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090048 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +090049 p.mk.filename = filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090050 p.outStmts = &p.mk.stmts
51 return p
52}
53
Shinichiro Hamajiae32b782015-03-31 14:41:19 +090054func (p *parser) addStatement(ast AST) {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +090055 *p.outStmts = append(*p.outStmts, ast)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090056}
57
Shinichiro Hamajie1841582015-03-30 17:20:33 +090058func (p *parser) readLine() []byte {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090059 if p.hasUnBuf {
60 p.hasUnBuf = false
61 return p.unBuf
Shinichiro Hamajie1841582015-03-30 17:20:33 +090062 }
63
Shinichiro Hamaji370be722015-04-10 14:55:23 +090064 if !p.linenoFixed {
65 p.lineno = p.elineno
66 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +090067 line, err := p.rd.ReadBytes('\n')
Shinichiro Hamaji370be722015-04-10 14:55:23 +090068 if !p.linenoFixed {
69 p.lineno++
70 p.elineno = p.lineno
71 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +090072 if err == io.EOF {
73 p.done = true
74 } else if err != nil {
Fumitoshi Ukaia9e51362015-04-17 10:26:00 +090075 panic(fmt.Errorf("readline %s:%d: %v", p.mk.filename, p.lineno, err))
Shinichiro Hamajie1841582015-03-30 17:20:33 +090076 }
77
Shinichiro Hamaji56c868c2015-04-09 10:17:10 +090078 line = bytes.TrimRight(line, "\r\n")
Shinichiro Hamajie1841582015-03-30 17:20:33 +090079
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +090080 return line
81}
82
83func removeComment(line []byte) []byte {
84 var parenStack []byte
Shinichiro Hamajif4d3ee52015-04-22 16:19:33 +090085 // Do not use range as we may modify |line| and |i|.
86 for i := 0; i < len(line); i++ {
87 ch := line[i]
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +090088 switch ch {
89 case '(', '{':
90 parenStack = append(parenStack, ch)
91 case ')', '}':
92 if len(parenStack) > 0 {
93 parenStack = parenStack[:len(parenStack)-1]
94 }
95 case '#':
96 if len(parenStack) == 0 {
Shinichiro Hamajif4d3ee52015-04-22 16:19:33 +090097 if i == 0 || line[i-1] != '\\' {
98 return line[:i]
99 }
100 // Drop the backslash before '#'.
101 line = append(line[:i-1], line[i:]...)
102 i--
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900103 }
104 }
105 }
106 return line
107}
108
Shinichiro Hamajie2f6e902015-04-22 16:08:47 +0900109func hasTrailingBackslash(line []byte) bool {
110 if len(line) == 0 {
111 return false
112 }
113 if line[len(line)-1] != '\\' {
114 return false
115 }
116 return len(line) <= 1 || line[len(line)-2] != '\\'
117}
118
Shinichiro Hamajie52c16c2015-04-11 23:41:39 +0900119func (p *parser) processDefineLine(line []byte) []byte {
Shinichiro Hamajie2f6e902015-04-22 16:08:47 +0900120 for hasTrailingBackslash(line) {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900121 line = line[:len(line)-1]
Shinichiro Hamajic4c98102015-04-12 03:56:00 +0900122 line = bytes.TrimRight(line, "\t ")
Shinichiro Hamaji3e4533d2015-04-06 14:03:58 +0900123 lineno := p.lineno
Shinichiro Hamajic4c98102015-04-12 03:56:00 +0900124 nline := trimLeftSpaceBytes(p.readLine())
Shinichiro Hamaji3e4533d2015-04-06 14:03:58 +0900125 p.lineno = lineno
Shinichiro Hamajic4c98102015-04-12 03:56:00 +0900126 line = append(line, ' ')
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900127 line = append(line, nline...)
128 }
Shinichiro Hamajie52c16c2015-04-11 23:41:39 +0900129 return line
130}
131
132func (p *parser) processMakefileLine(line []byte) []byte {
133 return removeComment(p.processDefineLine(line))
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900134}
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900135
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900136func (p *parser) processRecipeLine(line []byte) []byte {
Shinichiro Hamajie2f6e902015-04-22 16:08:47 +0900137 for hasTrailingBackslash(line) {
Shinichiro Hamaji52e83aa2015-04-06 17:20:28 +0900138 line = append(line, '\n')
139 lineno := p.lineno
140 nline := p.readLine()
141 p.lineno = lineno
142 line = append(line, nline...)
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900143 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900144 return line
145}
146
147func (p *parser) unreadLine(line []byte) {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900148 if p.hasUnBuf {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900149 panic("unreadLine twice!")
150 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900151 p.unBuf = line
152 p.hasUnBuf = true
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900153}
154
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900155func newAssignAST(p *parser, lhsBytes []byte, rhsBytes []byte, op string) *AssignAST {
156 lhs, _, err := parseExpr(lhsBytes, nil)
157 if err != nil {
158 panic(err)
159 }
160 rhs, _, err := parseExpr(rhsBytes, nil)
161 if err != nil {
162 panic(err)
163 }
164 opt := ""
165 if p != nil {
166 opt = p.defOpt
167 }
168 return &AssignAST{
169 lhs: lhs,
170 rhs: rhs,
171 op: op,
172 opt: opt,
173 }
174}
175
Fumitoshi Ukaie1b813c2015-03-30 18:38:21 +0900176func (p *parser) parseAssign(line []byte, sep, esep int) AST {
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900177 Logf("parseAssign %q op:%q", line, line[sep:esep])
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900178 ast := newAssignAST(p, bytes.TrimSpace(line[:sep]), trimLeftSpaceBytes(line[esep:]), string(line[sep:esep]))
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900179 ast.filename = p.mk.filename
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900180 ast.lineno = p.lineno
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900181 return ast
182}
183
Shinichiro Hamaji50309a62015-06-04 14:01:55 +0900184func (p *parser) parseMaybeRule(line []byte, equalIndex, semicolonIndex int) AST {
185 if len(trimSpaceBytes(line)) == 0 {
Shinichiro Hamajide829712015-03-31 18:26:56 +0900186 return nil
187 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900188
Shinichiro Hamaji171a3df2015-06-04 14:17:45 +0900189 expr := line
190 var term byte
191 var afterTerm []byte
192
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900193 // Either '=' or ';' is used.
194 if equalIndex >= 0 && semicolonIndex >= 0 {
195 if equalIndex < semicolonIndex {
196 semicolonIndex = -1
197 } else {
198 equalIndex = -1
199 }
200 }
Shinichiro Hamaji171a3df2015-06-04 14:17:45 +0900201 if semicolonIndex >= 0 {
202 afterTerm = expr[semicolonIndex:]
203 expr = expr[0:semicolonIndex]
204 term = ';'
205 } else if equalIndex >= 0 {
206 afterTerm = expr[equalIndex:]
207 expr = expr[0:equalIndex]
208 term = '='
209 }
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900210
Shinichiro Hamaji2d4b6052015-06-04 14:20:44 +0900211 v, _, err := parseExpr(expr, nil)
212 if err != nil {
213 panic(fmt.Errorf("parse %s:%d %v", p.mk.filename, p.lineno, err))
214 }
215
Shinichiro Hamaji486e9de2015-04-09 15:20:32 +0900216 ast := &MaybeRuleAST{
Shinichiro Hamaji2d4b6052015-06-04 14:20:44 +0900217 expr: v,
Shinichiro Hamaji171a3df2015-06-04 14:17:45 +0900218 term: term,
219 afterTerm: afterTerm,
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900220 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900221 ast.filename = p.mk.filename
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900222 ast.lineno = p.lineno
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900223 return ast
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900224}
225
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900226func (p *parser) parseInclude(line string, oplen int) AST {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900227 // TODO(ukai): parse expr here
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900228 ast := &IncludeAST{
229 expr: line[oplen+1:],
230 op: line[:oplen],
231 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900232 ast.filename = p.mk.filename
Shinichiro Hamajid7bef602015-03-30 19:55:32 +0900233 ast.lineno = p.lineno
234 return ast
235}
236
Shinichiro Hamaji61d2e112015-06-04 14:56:47 +0900237func (p *parser) parseIfdef(line []byte, oplen int) AST {
238 lhs, _, err := parseExpr(line[oplen+1:], nil)
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900239 if err != nil {
240 panic(fmt.Errorf("ifdef parse %s:%d %v", p.mk.filename, p.lineno, err))
241 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900242 ast := &IfAST{
Shinichiro Hamaji61d2e112015-06-04 14:56:47 +0900243 op: string(line[:oplen]),
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900244 lhs: lhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900245 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900246 ast.filename = p.mk.filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900247 ast.lineno = p.lineno
248 p.addStatement(ast)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900249 p.ifStack = append(p.ifStack, ifState{ast: ast, numNest: p.numIfNest})
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900250 p.outStmts = &ast.trueStmts
251 return ast
252}
253
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900254func (p *parser) parseTwoQuotes(s string, op string) ([]string, bool) {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900255 var args []string
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900256 for i := 0; i < 2; i++ {
257 s = strings.TrimSpace(s)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900258 if s == "" {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900259 return nil, false
260 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900261 quote := s[0]
262 if quote != '\'' && quote != '"' {
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900263 return nil, false
264 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900265 end := strings.IndexByte(s[1:], quote) + 1
266 if end < 0 {
267 return nil, false
268 }
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900269 args = append(args, s[1:end])
270 s = s[end+1:]
271 }
272 if len(s) > 0 {
273 Error(p.mk.filename, p.lineno, `extraneous text after %q directive`, op)
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900274 }
275 return args, true
276}
277
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900278// parse
279// "(lhs, rhs)"
280// "lhs, rhs"
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900281func (p *parser) parseEq(s string, op string) (string, string, bool) {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900282 if s[0] == '(' && s[len(s)-1] == ')' {
283 s = s[1 : len(s)-1]
284 term := []byte{','}
285 in := []byte(s)
286 v, n, err := parseExpr(in, term)
287 if err != nil {
288 return "", "", false
Shinichiro Hamaji76de43e2015-04-03 10:40:18 +0900289 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900290 lhs := v.String()
291 n++
292 n += skipSpaces(in[n:], nil)
293 v, n, err = parseExpr(in[n:], nil)
294 if err != nil {
295 return "", "", false
296 }
297 rhs := v.String()
298 return lhs, rhs, true
299 }
300 args, ok := p.parseTwoQuotes(s, op)
301 if !ok {
Fumitoshi Ukaie520f262015-03-31 17:27:03 +0900302 return "", "", false
303 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900304 return args[0], args[1], true
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900305}
306
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900307func (p *parser) parseIfeq(line string, oplen int) AST {
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900308 op := line[:oplen]
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900309 lhsBytes, rhsBytes, ok := p.parseEq(strings.TrimSpace(line[oplen+1:]), op)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900310 if !ok {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900311 Error(p.mk.filename, p.lineno, `*** invalid syntax in conditional.`)
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900312 }
313
Shinichiro Hamaji1a68fd22015-06-04 14:46:56 +0900314 lhs, _, err := parseExpr([]byte(lhsBytes), nil)
315 if err != nil {
316 panic(fmt.Errorf("parse ifeq lhs %s:%d %v", p.mk.filename, p.lineno, err))
317 }
318 rhs, _, err := parseExpr([]byte(rhsBytes), nil)
319 if err != nil {
320 panic(fmt.Errorf("parse ifeq rhs %s:%d %v", p.mk.filename, p.lineno, err))
321 }
322
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900323 ast := &IfAST{
Shinichiro Hamaji1f476382015-04-09 14:46:04 +0900324 op: op,
Shinichiro Hamajiaf1e8162015-03-31 02:15:37 +0900325 lhs: lhs,
326 rhs: rhs,
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900327 }
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900328 ast.filename = p.mk.filename
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900329 ast.lineno = p.lineno
330 p.addStatement(ast)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900331 p.ifStack = append(p.ifStack, ifState{ast: ast, numNest: p.numIfNest})
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900332 p.outStmts = &ast.trueStmts
333 return ast
334}
335
336func (p *parser) checkIfStack(curKeyword string) {
337 if len(p.ifStack) == 0 {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900338 Error(p.mk.filename, p.lineno, `*** extraneous %q.`, curKeyword)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900339 }
340}
341
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900342func (p *parser) parseElse(line []byte) {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900343 p.checkIfStack("else")
344 state := &p.ifStack[len(p.ifStack)-1]
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900345 if state.inElse {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900346 Error(p.mk.filename, p.lineno, `*** only one "else" per conditional.`)
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900347 }
Fumitoshi Ukai0293c7a2015-03-31 16:26:53 +0900348 state.inElse = true
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900349 p.outStmts = &state.ast.falseStmts
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900350
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900351 nextIf := trimLeftSpaceBytes(line[len("else"):])
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900352 if len(nextIf) == 0 {
353 return
354 }
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900355 var ifDirectives = map[string]directiveFunc{
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900356 "ifdef ": ifdefDirective,
357 "ifndef ": ifndefDirective,
358 "ifeq ": ifeqDirective,
359 "ifneq ": ifneqDirective,
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900360 }
361 p.numIfNest = state.numNest + 1
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900362 if f, ok := p.isDirective(nextIf, ifDirectives); ok {
363 f(p, nextIf)
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900364 p.numIfNest = 0
365 return
366 }
367 p.numIfNest = 0
368 WarnNoPrefix(p.mk.filename, p.lineno, "extraneous text after `else` directive")
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900369}
370
371func (p *parser) parseEndif(line string) {
372 p.checkIfStack("endif")
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900373 state := p.ifStack[len(p.ifStack)-1]
374 for t := 0; t <= state.numNest; t++ {
375 p.ifStack = p.ifStack[0 : len(p.ifStack)-1]
376 if len(p.ifStack) == 0 {
377 p.outStmts = &p.mk.stmts
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900378 } else {
Shinichiro Hamajia06760f2015-04-07 13:13:45 +0900379 state := p.ifStack[len(p.ifStack)-1]
380 if state.inElse {
381 p.outStmts = &state.ast.falseStmts
382 } else {
383 p.outStmts = &state.ast.trueStmts
384 }
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900385 }
386 }
387}
388
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900389type directiveFunc func(*parser, []byte) []byte
390
391var makeDirectives = map[string]directiveFunc{
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900392 "include ": includeDirective,
393 "-include ": sincludeDirective,
394 "sinclude": sincludeDirective,
395 "ifdef ": ifdefDirective,
396 "ifndef ": ifndefDirective,
397 "ifeq ": ifeqDirective,
398 "ifneq ": ifneqDirective,
399 "else": elseDirective,
400 "endif": endifDirective,
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900401 "define ": defineDirective,
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900402 "override ": overrideDirective,
403 "export ": exportDirective,
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900404 "unexport ": unexportDirective,
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900405}
406
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900407// TODO(ukai): use []byte
408func (p *parser) isDirective(line []byte, directives map[string]directiveFunc) (directiveFunc, bool) {
409 stripped := trimLeftSpaceBytes(line)
Shinichiro Hamajie103f652015-04-11 19:49:51 +0900410 // Fast paths.
411 // TODO: Consider using a trie.
412 if len(stripped) == 0 {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900413 return nil, false
Shinichiro Hamajie103f652015-04-11 19:49:51 +0900414 }
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900415 if ch := stripped[0]; ch != 'i' && ch != '-' && ch != 's' && ch != 'e' && ch != 'd' && ch != 'o' && ch != 'u' {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900416 return nil, false
Shinichiro Hamajie103f652015-04-11 19:49:51 +0900417 }
418
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900419 for prefix, f := range directives {
420 if bytes.HasPrefix(stripped, []byte(prefix)) {
421 return f, true
422 }
423 if prefix[len(prefix)-1] == ' ' && bytes.HasPrefix(stripped, []byte(prefix[:len(prefix)-1])) && stripped[len(prefix)-1] == '\t' {
424 return f, true
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900425 }
426 }
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900427 return nil, false
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900428}
429
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900430func includeDirective(p *parser, line []byte) []byte {
431 p.addStatement(p.parseInclude(string(line), len("include")))
432 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900433}
434
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900435func sincludeDirective(p *parser, line []byte) []byte {
436 p.addStatement(p.parseInclude(string(line), len("-include")))
437 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900438}
439
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900440func ifdefDirective(p *parser, line []byte) []byte {
Shinichiro Hamaji61d2e112015-06-04 14:56:47 +0900441 p.parseIfdef(line, len("ifdef"))
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900442 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900443}
444
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900445func ifndefDirective(p *parser, line []byte) []byte {
Shinichiro Hamaji61d2e112015-06-04 14:56:47 +0900446 p.parseIfdef(line, len("ifndef"))
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900447 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900448}
449
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900450func ifeqDirective(p *parser, line []byte) []byte {
451 p.parseIfeq(string(line), len("ifeq"))
452 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900453}
454
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900455func ifneqDirective(p *parser, line []byte) []byte {
456 p.parseIfeq(string(line), len("ifneq"))
457 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900458}
459
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900460func elseDirective(p *parser, line []byte) []byte {
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900461 p.parseElse(line)
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900462 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900463}
464
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900465func endifDirective(p *parser, line []byte) []byte {
466 p.parseEndif(string(line))
467 return nil
Fumitoshi Ukai82096302015-04-01 10:37:47 +0900468}
469
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900470func defineDirective(p *parser, line []byte) []byte {
471 lhs := trimLeftSpaceBytes(line[len("define "):])
472 p.inDef = []string{string(lhs)}
473 return nil
474}
475
476func overrideDirective(p *parser, line []byte) []byte {
477 p.defOpt = "override"
478 line = trimLeftSpaceBytes(line[len("override "):])
479 defineDirective := map[string]directiveFunc{
480 "define": defineDirective,
481 }
482 if f, ok := p.isDirective(line, defineDirective); ok {
483 f(p, line)
484 return nil
485 }
486 // e.g. overrider foo := bar
487 // line will be "foo := bar".
488 return line
489}
490
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900491func handleExport(p *parser, line []byte, export bool) (hasEqual bool) {
492 equalIndex := bytes.IndexByte(line, '=')
493 if equalIndex > 0 {
494 hasEqual = true
495 switch line[equalIndex-1] {
496 case ':', '+', '?':
497 equalIndex--
498 }
499 line = line[:equalIndex]
500 }
501
Shinichiro Hamajif61033d2015-05-29 15:01:48 +0900502 ast := &ExportAST{
503 expr: line,
504 export: export,
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900505 }
Shinichiro Hamajif61033d2015-05-29 15:01:48 +0900506 ast.filename = p.mk.filename
507 ast.lineno = p.lineno
508 p.addStatement(ast)
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900509 return hasEqual
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900510}
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900511
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900512func exportDirective(p *parser, line []byte) []byte {
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900513 p.defOpt = "export"
514 line = trimLeftSpaceBytes(line[len("export "):])
515 defineDirective := map[string]directiveFunc{
516 "define": defineDirective,
517 }
518 if f, ok := p.isDirective(line, defineDirective); ok {
519 f(p, line)
520 return nil
521 }
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900522
Shinichiro Hamajiea553f32015-05-29 17:03:33 +0900523 if !handleExport(p, line, true) {
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900524 return nil
525 }
526
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900527 // e.g. export foo := bar
528 // line will be "foo := bar".
529 return line
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900530}
531
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900532func unexportDirective(p *parser, line []byte) []byte {
Shinichiro Hamaji7e521422015-05-29 14:23:30 +0900533 handleExport(p, line[len("unexport "):], false)
Shinichiro Hamaji07e76d52015-05-26 18:22:31 +0900534 return nil
535}
536
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900537func (p *parser) parse() (mk Makefile, err error) {
538 defer func() {
539 if r := recover(); r != nil {
Fumitoshi Ukaia9e51362015-04-17 10:26:00 +0900540 err = fmt.Errorf("panic in parse %s: %v", mk.filename, r)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900541 }
542 }()
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900543 for !p.done {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900544 line := p.readLine()
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900545
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900546 if len(p.inDef) > 0 {
Shinichiro Hamajie52c16c2015-04-11 23:41:39 +0900547 line = p.processDefineLine(line)
Shinichiro Hamajic88618f2015-04-11 19:58:06 +0900548 if trimLeftSpace(string(line)) == "endef" {
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900549 Logf("multilineAssign %q", p.inDef)
Shinichiro Hamaji7825b652015-06-04 13:47:14 +0900550 ast := newAssignAST(p, []byte(p.inDef[0]), []byte(strings.Join(p.inDef[1:], "\n")), "=")
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900551 ast.filename = p.mk.filename
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900552 ast.lineno = p.lineno - len(p.inDef)
553 p.addStatement(ast)
554 p.inDef = nil
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900555 p.defOpt = ""
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900556 continue
557 }
558 p.inDef = append(p.inDef, string(line))
559 continue
560 }
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900561 p.defOpt = ""
Fumitoshi Ukai3d54db82015-04-01 11:03:31 +0900562
Shinichiro Hamaji960161f2015-04-13 17:10:10 +0900563 if len(bytes.TrimSpace(line)) == 0 {
564 continue
565 }
566
Fumitoshi Ukaib2c300f2015-04-23 00:59:26 +0900567 if f, ok := p.isDirective(line, makeDirectives); ok {
568 line = p.processMakefileLine(trimLeftSpaceBytes(line))
569 line = f(p, line)
570 if len(line) == 0 {
571 continue
572 }
Shinichiro Hamaji74b8cb52015-04-08 19:47:43 +0900573 }
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900574 if line[0] == '\t' {
575 ast := &CommandAST{cmd: string(p.processRecipeLine(line[1:]))}
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900576 ast.filename = p.mk.filename
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900577 ast.lineno = p.lineno
578 p.addStatement(ast)
579 continue
580 }
581
582 line = p.processMakefileLine(line)
Shinichiro Hamajia66a1792015-03-31 18:04:08 +0900583
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900584 var ast AST
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900585 var parenStack []byte
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900586 equalIndex := -1
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900587 semicolonIndex := -1
588 isRule := false
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900589 for i, ch := range line {
590 switch ch {
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900591 case '(', '{':
592 parenStack = append(parenStack, ch)
593 case ')', '}':
594 if len(parenStack) == 0 {
Shinichiro Hamaji491e73f2015-04-07 12:41:59 +0900595 Warn(p.mk.filename, p.lineno, "Unmatched parens: %s", line)
Shinichiro Hamaji34e23242015-04-06 15:44:50 +0900596 } else {
597 parenStack = parenStack[:len(parenStack)-1]
598 }
599 }
600 if len(parenStack) > 0 {
601 continue
602 }
603
604 switch ch {
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900605 case ':':
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900606 if i+1 < len(line) && line[i+1] == '=' {
Shinichiro Hamaji156ef3e2015-04-11 22:44:41 +0900607 if !isRule {
608 ast = p.parseAssign(line, i, i+2)
609 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900610 } else {
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900611 isRule = true
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900612 }
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900613 case ';':
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900614 if semicolonIndex < 0 {
615 semicolonIndex = i
616 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900617 case '=':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900618 if !isRule {
619 ast = p.parseAssign(line, i, i+1)
620 }
Shinichiro Hamajie12e24d2015-04-11 23:09:20 +0900621 if equalIndex < 0 {
622 equalIndex = i
623 }
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900624 case '?', '+':
Shinichiro Hamaji3fab47e2015-04-08 18:34:41 +0900625 if !isRule && i+1 < len(line) && line[i+1] == '=' {
Shinichiro Hamaji69b7f652015-03-31 01:01:59 +0900626 ast = p.parseAssign(line, i, i+2)
627 }
Shinichiro Hamajie1841582015-03-30 17:20:33 +0900628 }
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900629 if ast != nil {
Shinichiro Hamaji497754d2015-03-31 02:02:11 +0900630 p.addStatement(ast)
Shinichiro Hamaji7f1ede32015-03-30 18:05:22 +0900631 break
632 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900633 }
Shinichiro Hamajide829712015-03-31 18:26:56 +0900634 if ast == nil {
Shinichiro Hamaji50309a62015-06-04 14:01:55 +0900635 ast = p.parseMaybeRule(line, equalIndex, semicolonIndex)
Shinichiro Hamajide829712015-03-31 18:26:56 +0900636 if ast != nil {
637 p.addStatement(ast)
638 }
Shinichiro Hamaji685fecf2015-03-30 18:28:12 +0900639 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900640 }
641 return p.mk, nil
642}
643
Shinichiro Hamaji290eb252015-05-19 18:03:19 +0900644func ParseMakefileFd(filename string, f *os.File) (Makefile, error) {
645 parser := newParser(f, filename)
646 return parser.parse()
647}
648
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900649/*
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900650func ParseMakefile(filename string) (Makefile, error) {
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900651 Logf("ParseMakefile %q", filename)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900652 f, err := os.Open(filename)
653 if err != nil {
654 return Makefile{}, err
655 }
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900656 defer f.Close()
Shinichiro Hamaji290eb252015-05-19 18:03:19 +0900657 return ParseMakefileFd(filename, f)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900658}
659
Shinichiro Hamaji750ae2e2015-05-20 12:59:15 +0900660func ParseDefaultMakefile() (Makefile, string, error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900661 candidates := []string{"GNUmakefile", "makefile", "Makefile"}
662 for _, filename := range candidates {
663 if exists(filename) {
Shinichiro Hamaji750ae2e2015-05-20 12:59:15 +0900664 mk, err := ParseMakefile(filename)
665 return mk, filename, err
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900666 }
667 }
Shinichiro Hamaji750ae2e2015-05-20 12:59:15 +0900668 return Makefile{}, "", errors.New("no targets specified and no makefile found.")
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900669}
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900670*/
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900671
Shinichiro Hamajib0d2e2f2015-05-20 16:42:59 +0900672func GetDefaultMakefile() string {
673 candidates := []string{"GNUmakefile", "makefile", "Makefile"}
674 for _, filename := range candidates {
675 if exists(filename) {
676 return filename
677 }
678 }
679 ErrorNoLocation("no targets specified and no makefile found.")
680 panic("") // Cannot be reached.
681}
682
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900683func parseMakefileReader(rd io.Reader, name string, lineno int) (Makefile, error) {
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900684 parser := newParser(rd, name)
Shinichiro Hamaji370be722015-04-10 14:55:23 +0900685 parser.lineno = lineno
Shinichiro Hamaji29ffc972015-04-06 16:13:27 +0900686 parser.elineno = lineno
Shinichiro Hamaji370be722015-04-10 14:55:23 +0900687 parser.linenoFixed = true
Shinichiro Hamajia5dee372015-04-03 16:41:30 +0900688 return parser.parse()
Shinichiro Hamajic3840812015-04-02 02:10:20 +0900689}
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900690
691func ParseMakefileString(s string, name string, lineno int) (Makefile, error) {
692 return parseMakefileReader(strings.NewReader(s), name, lineno)
693}
694
695func ParseMakefileBytes(s []byte, name string, lineno int) (Makefile, error) {
696 return parseMakefileReader(bytes.NewReader(s), name, lineno)
697}
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900698
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900699type MakefileCache struct {
700 mk Makefile
701 err error
702 ts int64
703}
704
705var makefileCache map[string]MakefileCache
706
707func InitMakefileCache() {
708 if makefileCache == nil {
709 makefileCache = make(map[string]MakefileCache)
710 }
711}
712
713func LookupMakefileCache(filename string) (Makefile, error, bool) {
714 c, present := makefileCache[filename]
715 if !present {
716 return Makefile{}, nil, false
717 }
718 ts := getTimestamp(filename)
719 if ts < 0 || ts >= c.ts {
720 return Makefile{}, nil, false
721 }
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900722 Logf("Cache hit for %q", filename)
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900723 return c.mk, c.err, true
724}
725
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900726func ParseMakefile(s []byte, filename string) (Makefile, error) {
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900727 Logf("ParseMakefile %q", filename)
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900728 parser := newParser(bytes.NewReader(s), filename)
Shinichiro Hamaji584bb062015-06-04 13:25:13 +0900729 mk, err := parser.parse()
730 makefileCache[filename] = MakefileCache{
731 mk: mk,
732 err: err,
733 ts: time.Now().Unix(),
734 }
735 return mk, err
Shinichiro Hamaji45cde1d2015-05-25 18:21:23 +0900736}