blob: 8b8fef7ca20845d7f98a594dd2ae349a7162c483 [file] [log] [blame]
Shinichiro Hamaji04932612015-03-31 23:46:56 +09001package main
2
3import (
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +09004 "errors"
Shinichiro Hamaji04932612015-03-31 23:46:56 +09005 "strings"
6)
7
8type Rule struct {
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +09009 outputs []string
10 inputs []string
11 orderOnlyInputs []string
12 outputPatterns []string
13 isDoubleColon bool
14 isSuffixRule bool
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +090015 vars *VarTab
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +090016 cmds []string
17 filename string
18 lineno int
19 cmdLineno int
Shinichiro Hamaji04932612015-03-31 23:46:56 +090020}
21
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +090022func isPatternRule(s string) bool {
23 return strings.IndexByte(s, '%') >= 0
24}
25
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +090026func (r *Rule) parseInputs(s string) {
27 inputs := splitSpaces(s)
28 isOrderOnly := false
29 for _, input := range inputs {
30 if input == "|" {
31 isOrderOnly = true
32 continue
33 }
34 if isOrderOnly {
35 r.orderOnlyInputs = append(r.orderOnlyInputs, input)
36 } else {
37 r.inputs = append(r.inputs, input)
38 }
39 }
40}
41
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +090042func (r *Rule) parseVar(s string) *AssignAST {
43 eq := strings.IndexByte(s, '=')
44 if eq <= 0 {
45 return nil
46 }
47 assign := &AssignAST{
48 rhs: strings.TrimLeft(s[eq+1:], " \t"),
49 }
50 assign.filename = r.filename
51 assign.lineno = r.lineno
52 // TODO(ukai): support override, export.
Fumitoshi Ukai3ef5fcc2015-04-06 17:21:43 +090053 switch s[eq-1 : eq+1] {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +090054 case ":=":
55 assign.lhs = strings.TrimSpace(s[:eq-1])
56 assign.op = ":="
57 case "+=":
58 assign.lhs = strings.TrimSpace(s[:eq-1])
59 assign.op = "+="
60 case "?=":
61 assign.lhs = strings.TrimSpace(s[:eq-1])
62 assign.op = "?="
63 default:
64 assign.lhs = strings.TrimSpace(s[:eq])
65 assign.op = "="
66 }
67 return assign
68}
69
70func (r *Rule) parse(line string) (*AssignAST, error) {
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +090071 index := strings.IndexByte(line, ':')
72 if index < 0 {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +090073 return nil, errors.New("*** missing separator.")
Shinichiro Hamaji04932612015-03-31 23:46:56 +090074 }
75
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +090076 first := line[:index]
77 outputs := splitSpaces(first)
78 isFirstPattern := isPatternRule(first)
79 if isFirstPattern {
80 if len(outputs) > 1 {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +090081 return nil, errors.New("*** mixed implicit and normal rules: deprecated syntax")
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +090082 }
83 r.outputPatterns = outputs
84 } else {
85 r.outputs = outputs
86 }
87
88 index++
89 if index < len(line) && line[index] == ':' {
90 r.isDoubleColon = true
91 index++
92 }
93
94 rest := line[index:]
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +090095 if assign := r.parseVar(rest); assign != nil {
96 return assign, nil
97 }
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +090098 index = strings.IndexByte(rest, ':')
99 if index < 0 {
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900100 r.parseInputs(rest)
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900101 return nil, nil
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +0900102 }
103
104 // %.x: %.y: %.z
105 if isFirstPattern {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900106 return nil, errors.New("*** mixed implicit and normal rules: deprecated syntax")
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +0900107 }
108
109 second := rest[:index]
110 third := rest[index+1:]
111
112 r.outputs = outputs
113 r.outputPatterns = splitSpaces(second)
114 if len(r.outputPatterns) == 0 {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900115 return nil, errors.New("*** missing target pattern.")
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +0900116 }
117 if len(r.outputPatterns) > 1 {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900118 return nil, errors.New("*** multiple target patterns.")
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +0900119 }
120 if !isPatternRule(r.outputPatterns[0]) {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900121 return nil, errors.New("*** target pattern contains no '%'.")
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +0900122 }
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900123 r.parseInputs(third)
Shinichiro Hamaji21a9b5f2015-04-01 02:42:59 +0900124
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900125 return nil, nil
Shinichiro Hamaji04932612015-03-31 23:46:56 +0900126}