blob: 095ab7578499a4dbfbfdec11a2550bf565f41e54 [file] [log] [blame]
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +09001package main
2
3import (
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +09004 "bytes"
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +09005 "fmt"
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +09006 "io"
Shinichiro Hamajie7aafb02015-04-09 18:23:46 +09007 "os"
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +09008 "os/exec"
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +09009 "path/filepath"
Shinichiro Hamaji13b30d92015-04-03 14:42:21 +090010 "sort"
Shinichiro Hamajie708a9d2015-04-03 14:34:35 +090011 "strconv"
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090012 "strings"
13)
14
15// Func is a make function.
16// http://www.gnu.org/software/make/manual/make.html#Functions
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090017
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090018// Func is make builtin function.
19type Func interface {
20 // Arity is max function's arity.
21 // ',' will not be handled as argument separator more than arity.
22 // 0 means varargs.
23 Arity() int
24
25 // AddArg adds value as an argument.
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +090026 // the first argument will be "(funcname", or "{funcname".
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090027 AddArg(Value)
28
29 Value
30}
31
32var (
33 funcMap = map[string]func() Func{
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +090034 "patsubst": func() Func { return &funcPatsubst{} },
35 "strip": func() Func { return &funcStrip{} },
36 "subst": func() Func { return &funcSubst{} },
37 "findstring": func() Func { return &funcFindstring{} },
38 "filter": func() Func { return &funcFilter{} },
39 "filter-out": func() Func { return &funcFilterOut{} },
40 "sort": func() Func { return &funcSort{} },
41 "word": func() Func { return &funcWord{} },
42 "wordlist": func() Func { return &funcWordlist{} },
43 "words": func() Func { return &funcWords{} },
44 "firstword": func() Func { return &funcFirstword{} },
45 "lastword": func() Func { return &funcLastword{} },
46
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +090047 "join": func() Func { return &funcJoin{} },
48 "wildcard": func() Func { return &funcWildcard{} },
49 "dir": func() Func { return &funcDir{} },
50 "notdir": func() Func { return &funcNotdir{} },
51 "suffix": func() Func { return &funcSuffix{} },
52 "basename": func() Func { return &funcBasename{} },
53 "addsuffix": func() Func { return &funcAddsuffix{} },
54 "addprefix": func() Func { return &funcAddprefix{} },
55 "realpath": func() Func { return &funcRealpath{} },
56 "abspath": func() Func { return &funcAbspath{} },
57
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +090058 "if": func() Func { return &funcIf{} },
59 "and": func() Func { return &funcAnd{} },
60 "or": func() Func { return &funcOr{} },
61
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +090062 "value": func() Func { return &funcValue{} },
63
64 "eval": func() Func { return &funcEval{} },
65
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +090066 "shell": func() Func { return &funcShell{} },
67 "call": func() Func { return &funcCall{} },
68 "foreach": func() Func { return &funcForeach{} },
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +090069
70 "origin": func() Func { return &funcOrigin{} },
71 "flavor": func() Func { return &funcFlavor{} },
72 "info": func() Func { return &funcInfo{} },
73 "warning": func() Func { return &funcWarning{} },
74 "error": func() Func { return &funcError{} },
Fumitoshi Ukai0b5e18b2015-04-03 22:57:17 +090075 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090076)
77
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090078func assertArity(name string, req, n int) {
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +090079 if n-1 < req {
80 panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `%s'.", n-1, name))
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090081 }
82}
83
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +090084// A space separated values writer.
85type ssvWriter struct {
86 w io.Writer
87 needsSpace bool
88}
89
90func (sw *ssvWriter) Write(b []byte) {
91 if sw.needsSpace {
92 sw.w.Write([]byte{' '})
93 }
94 sw.needsSpace = true
95 sw.w.Write(b)
96}
97
Shinichiro Hamajia1358912015-04-11 12:16:21 +090098func (sw *ssvWriter) WriteString(s string) {
99 // TODO: Ineffcient. Nice if we can remove the cast.
100 sw.Write([]byte(s))
101}
102
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900103func numericValueForFunc(ev *Evaluator, v Value, funcName string, nth string) int {
104 a := bytes.TrimSpace(ev.Value(v))
105 n, err := strconv.Atoi(string(a))
106 if err != nil || n < 0 {
107 Error(ev.filename, ev.lineno, `*** non-numeric %s argument to "%s" function: "%s".`, nth, funcName, a)
108 }
109 return n
110}
111
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900112type fclosure struct {
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900113 // args[0] is "(funcname", or "{funcname".
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900114 args []Value
115}
116
117func (c *fclosure) AddArg(v Value) {
118 c.args = append(c.args, v)
Fumitoshi Ukai0b5e18b2015-04-03 22:57:17 +0900119}
120
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900121func (c *fclosure) String() string {
122 if len(c.args) == 0 {
123 panic("no args in func")
124 }
125 arg0 := c.args[0].String()
126 if arg0 == "" {
127 panic(fmt.Errorf("wrong format of arg0: %q", arg0))
128 }
129 cp := closeParen(arg0[0])
130 if cp == 0 {
131 panic(fmt.Errorf("wrong format of arg0: %q", arg0))
132 }
133 var args []string
134 for _, arg := range c.args[1:] {
135 args = append(args, arg.String())
136 }
137 return fmt.Sprintf("$%s %s%c", arg0, strings.Join(args, ","), cp)
138}
Fumitoshi Ukai78781132015-04-10 17:08:40 +0900139
Shinichiro Hamaji4125cf42015-04-03 11:42:28 +0900140// http://www.gnu.org/software/make/manual/make.html#Text-Functions
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900141type funcSubst struct{ fclosure }
142
143func (f *funcSubst) Arity() int { return 3 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900144func (f *funcSubst) Eval(w io.Writer, ev *Evaluator) {
145 assertArity("subst", 3, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900146 from := ev.Value(f.args[1])
147 to := ev.Value(f.args[2])
148 text := ev.Value(f.args[3])
Fumitoshi Ukaibb79a9d2015-04-02 12:46:54 +0900149 Log("subst from:%q to:%q text:%q", from, to, text)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900150 w.Write(bytes.Replace(text, from, to, -1))
151}
152
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900153type funcPatsubst struct{ fclosure }
154
155func (f *funcPatsubst) Arity() int { return 3 }
156func (f *funcPatsubst) Eval(w io.Writer, ev *Evaluator) {
157 assertArity("patsubst", 3, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900158 pat := ev.Value(f.args[1])
159 repl := ev.Value(f.args[2])
160 texts := splitSpacesBytes(ev.Value(f.args[3]))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900161 sw := ssvWriter{w: w}
162 for _, text := range texts {
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900163 t := substPatternBytes(pat, repl, text)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900164 sw.Write(t)
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900165 }
166}
167
168type funcStrip struct{ fclosure }
169
170func (f *funcStrip) Arity() int { return 1 }
171func (f *funcStrip) Eval(w io.Writer, ev *Evaluator) {
172 assertArity("strip", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900173 text := ev.Value(f.args[1])
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900174 w.Write(bytes.TrimSpace(text))
175}
176
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900177type funcFindstring struct{ fclosure }
178
179func (f *funcFindstring) Arity() int { return 2 }
180func (f *funcFindstring) Eval(w io.Writer, ev *Evaluator) {
181 assertArity("findstring", 2, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900182 find := ev.Value(f.args[1])
183 text := ev.Value(f.args[2])
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900184 if bytes.Index(text, find) >= 0 {
185 w.Write(find)
186 }
187}
188
189type funcFilter struct{ fclosure }
190
191func (f *funcFilter) Arity() int { return 2 }
192func (f *funcFilter) Eval(w io.Writer, ev *Evaluator) {
193 assertArity("filter", 2, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900194 patterns := splitSpacesBytes(ev.Value(f.args[1]))
195 texts := splitSpacesBytes(ev.Value(f.args[2]))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900196 sw := ssvWriter{w: w}
197 for _, text := range texts {
198 for _, pat := range patterns {
199 if matchPatternBytes(pat, text) {
200 sw.Write(text)
201 }
202 }
203 }
204}
205
206type funcFilterOut struct{ fclosure }
207
208func (f *funcFilterOut) Arity() int { return 2 }
209func (f *funcFilterOut) Eval(w io.Writer, ev *Evaluator) {
210 assertArity("filter-out", 2, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900211 patterns := splitSpacesBytes(ev.Value(f.args[1]))
212 texts := splitSpacesBytes(ev.Value(f.args[2]))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900213 sw := ssvWriter{w: w}
214Loop:
215 for _, text := range texts {
216 for _, pat := range patterns {
217 if matchPatternBytes(pat, text) {
218 continue Loop
219 }
220 }
221 sw.Write(text)
222 }
223}
224
225type funcSort struct{ fclosure }
226
227func (f *funcSort) Arity() int { return 1 }
228func (f *funcSort) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900229 assertArity("sort", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900230 toks := splitSpaces(string(ev.Value(f.args[1])))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900231 sort.Strings(toks)
232
233 // Remove duplicate words.
234 var prev string
235 sw := ssvWriter{w: w}
236 for _, tok := range toks {
237 if prev != tok {
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900238 sw.WriteString(tok)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900239 prev = tok
240 }
241 }
242}
243
244type funcWord struct{ fclosure }
245
246func (f *funcWord) Arity() int { return 2 }
247func (f *funcWord) Eval(w io.Writer, ev *Evaluator) {
248 assertArity("word", 2, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900249 index := numericValueForFunc(ev, f.args[1], "word", "first")
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900250 if index == 0 {
251 Error(ev.filename, ev.lineno, `*** first argument to "word" function must be greater than 0.`)
252 }
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900253 toks := splitSpacesBytes(ev.Value(f.args[2]))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900254 if index-1 >= len(toks) {
255 return
256 }
257 w.Write(toks[index-1])
258}
259
260type funcWordlist struct{ fclosure }
261
262func (f *funcWordlist) Arity() int { return 3 }
263func (f *funcWordlist) Eval(w io.Writer, ev *Evaluator) {
264 assertArity("wordlist", 3, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900265 si := numericValueForFunc(ev, f.args[1], "wordlist", "first")
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900266 if si == 0 {
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900267 Error(ev.filename, ev.lineno, `*** invalid first argument to "wordlist" function: %s`, f.args[1])
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900268 }
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900269 ei := numericValueForFunc(ev, f.args[2], "wordlist", "second")
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900270 if ei == 0 {
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900271 Error(ev.filename, ev.lineno, `*** invalid second argument to "wordlist" function: %s`, f.args[2])
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900272 }
273
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900274 toks := splitSpacesBytes(ev.Value(f.args[3]))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900275 if si-1 >= len(toks) {
276 return
277 }
278 if ei-1 >= len(toks) {
279 ei = len(toks)
280 }
281
282 sw := ssvWriter{w: w}
283 for _, t := range toks[si-1 : ei] {
284 sw.Write(t)
285 }
286}
287
288type funcWords struct{ fclosure }
289
290func (f *funcWords) Arity() int { return 1 }
291func (f *funcWords) Eval(w io.Writer, ev *Evaluator) {
292 assertArity("words", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900293 toks := splitSpacesBytes(ev.Value(f.args[1]))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900294 w.Write([]byte(strconv.Itoa(len(toks))))
295}
296
297type funcFirstword struct{ fclosure }
298
299func (f *funcFirstword) Arity() int { return 1 }
300func (f *funcFirstword) Eval(w io.Writer, ev *Evaluator) {
301 assertArity("firstword", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900302 toks := splitSpacesBytes(ev.Value(f.args[1]))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900303 if len(toks) == 0 {
304 return
305 }
306 w.Write(toks[0])
307}
308
309type funcLastword struct{ fclosure }
310
311func (f *funcLastword) Arity() int { return 1 }
312func (f *funcLastword) Eval(w io.Writer, ev *Evaluator) {
313 assertArity("lastword", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900314 toks := splitSpacesBytes(ev.Value(f.args[1]))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900315 if len(toks) == 0 {
316 return
317 }
318 w.Write(toks[len(toks)-1])
319}
320
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900321// https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html#File-Name-Functions
322
323type funcJoin struct{ fclosure }
324
325func (f *funcJoin) Arity() int { return 2 }
326func (f *funcJoin) Eval(w io.Writer, ev *Evaluator) {
327 assertArity("join", 2, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900328 list1 := splitSpacesBytes(ev.Value(f.args[1]))
329 list2 := splitSpacesBytes(ev.Value(f.args[2]))
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900330 sw := ssvWriter{w: w}
331 for i, v := range list1 {
332 if i < len(list2) {
333 sw.Write(v)
334 // Use |w| not to append extra ' '.
335 w.Write(list2[i])
336 continue
337 }
338 sw.Write(v)
339 }
340 if len(list2) > len(list1) {
341 for _, v := range list2[len(list1):] {
342 sw.Write(v)
343 }
344 }
345}
346
347type funcWildcard struct{ fclosure }
348
349func (f *funcWildcard) Arity() int { return 1 }
350func (f *funcWildcard) Eval(w io.Writer, ev *Evaluator) {
351 assertArity("wildcard", 1, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900352 sw := ssvWriter{w: w}
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900353 for _, pattern := range splitSpaces(string(ev.Value(f.args[1]))) {
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900354 files, err := filepath.Glob(pattern)
355 if err != nil {
356 panic(err)
357 }
358 for _, file := range files {
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900359 sw.WriteString(file)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900360 }
361 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900362}
363
364type funcDir struct{ fclosure }
365
366func (f *funcDir) Arity() int { return 1 }
367func (f *funcDir) Eval(w io.Writer, ev *Evaluator) {
368 assertArity("dir", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900369 names := splitSpaces(string(ev.Value(f.args[1])))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900370 sw := ssvWriter{w: w}
371 for _, name := range names {
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900372 sw.WriteString(filepath.Dir(name) + string(filepath.Separator))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900373 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900374}
375
376type funcNotdir struct{ fclosure }
377
378func (f *funcNotdir) Arity() int { return 1 }
379func (f *funcNotdir) Eval(w io.Writer, ev *Evaluator) {
380 assertArity("notdir", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900381 names := splitSpaces(string(ev.Value(f.args[1])))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900382 sw := ssvWriter{w: w}
383 for _, name := range names {
384 if name == string(filepath.Separator) {
385 sw.Write([]byte{})
386 continue
387 }
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900388 sw.WriteString(filepath.Base(name))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900389 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900390}
391
392type funcSuffix struct{ fclosure }
393
394func (f *funcSuffix) Arity() int { return 1 }
395func (f *funcSuffix) Eval(w io.Writer, ev *Evaluator) {
396 assertArity("suffix", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900397 toks := splitSpaces(string(ev.Value(f.args[1])))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900398 sw := ssvWriter{w: w}
399 for _, tok := range toks {
400 e := filepath.Ext(tok)
401 if len(e) > 0 {
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900402 sw.WriteString(e)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900403 }
404 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900405}
406
407type funcBasename struct{ fclosure }
408
409func (f *funcBasename) Arity() int { return 1 }
410func (f *funcBasename) Eval(w io.Writer, ev *Evaluator) {
411 assertArity("basename", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900412 toks := splitSpaces(string(ev.Value(f.args[1])))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900413 sw := ssvWriter{w: w}
414 for _, tok := range toks {
415 e := stripExt(tok)
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900416 sw.WriteString(e)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900417 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900418}
419
420type funcAddsuffix struct{ fclosure }
421
422func (f *funcAddsuffix) Arity() int { return 2 }
423func (f *funcAddsuffix) Eval(w io.Writer, ev *Evaluator) {
424 assertArity("addsuffix", 2, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900425 suf := ev.Value(f.args[1])
426 toks := splitSpacesBytes(ev.Value(f.args[2]))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900427 sw := ssvWriter{w: w}
428 for _, tok := range toks {
429 sw.Write(tok)
430 // Use |w| not to append extra ' '.
431 w.Write(suf)
432 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900433}
434
435type funcAddprefix struct{ fclosure }
436
437func (f *funcAddprefix) Arity() int { return 2 }
438func (f *funcAddprefix) Eval(w io.Writer, ev *Evaluator) {
439 assertArity("addprefix", 2, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900440 pre := ev.Value(f.args[1])
441 toks := splitSpacesBytes(ev.Value(f.args[2]))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900442 sw := ssvWriter{w: w}
443 for _, tok := range toks {
444 sw.Write(pre)
445 // Use |w| not to append extra ' '.
446 w.Write(tok)
447 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900448}
449
450type funcRealpath struct{ fclosure }
451
452func (f *funcRealpath) Arity() int { return 1 }
453func (f *funcRealpath) Eval(w io.Writer, ev *Evaluator) {
454 assertArity("realpath", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900455 names := splitSpaces(string(ev.Value(f.args[1])))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900456 sw := ssvWriter{w: w}
457 for _, name := range names {
458 name, err := filepath.Abs(name)
459 if err != nil {
460 Log("abs: %v", err)
461 continue
462 }
463 name, err = filepath.EvalSymlinks(name)
464 if err != nil {
465 Log("realpath: %v", err)
466 continue
467 }
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900468 sw.WriteString(name)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900469 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900470}
471
472type funcAbspath struct{ fclosure }
473
474func (f *funcAbspath) Arity() int { return 1 }
475func (f *funcAbspath) Eval(w io.Writer, ev *Evaluator) {
476 assertArity("abspath", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900477 names := splitSpaces(string(ev.Value(f.args[1])))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900478 sw := ssvWriter{w: w}
479 for _, name := range names {
480 name, err := filepath.Abs(name)
481 if err != nil {
482 Log("abs: %v", err)
483 continue
484 }
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900485 sw.WriteString(name)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900486 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900487}
488
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900489// http://www.gnu.org/software/make/manual/make.html#Conditional-Functions
490type funcIf struct{ fclosure }
491
492func (f *funcIf) Arity() int { return 3 }
493func (f *funcIf) Eval(w io.Writer, ev *Evaluator) {
494 assertArity("if", 2, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900495 cond := ev.Value(f.args[1])
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900496 if len(cond) != 0 {
Fumitoshi Ukaie27a25d2015-04-18 00:31:01 +0900497 f.args[2].Eval(w, ev)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900498 return
499 }
Fumitoshi Ukaie27a25d2015-04-18 00:31:01 +0900500 if len(f.args) > 3 {
501 f.args[3].Eval(w, ev)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900502 }
503}
504
505type funcAnd struct{ fclosure }
506
507func (f *funcAnd) Arity() int { return 0 }
508func (f *funcAnd) Eval(w io.Writer, ev *Evaluator) {
509 assertArity("and", 0, len(f.args))
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900510 var cond []byte
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900511 for _, arg := range f.args[1:] {
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900512 cond = ev.Value(arg)
513 if len(cond) == 0 {
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900514 return
515 }
516 }
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900517 w.Write(cond)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900518}
519
520type funcOr struct{ fclosure }
521
522func (f *funcOr) Arity() int { return 0 }
523func (f *funcOr) Eval(w io.Writer, ev *Evaluator) {
524 assertArity("or", 0, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900525 for _, arg := range f.args[1:] {
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900526 cond := ev.Value(arg)
527 if len(cond) != 0 {
528 w.Write(cond)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900529 return
530 }
531 }
532}
533
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900534// http://www.gnu.org/software/make/manual/make.html#Shell-Function
535type funcShell struct{ fclosure }
536
537func (f *funcShell) Arity() int { return 1 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900538
539func (f *funcShell) Eval(w io.Writer, ev *Evaluator) {
540 assertArity("shell", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900541 arg := ev.Value(f.args[1])
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900542 shellVar := ev.LookupVar("SHELL")
543 // TODO: Should be Eval, not String.
544 cmdline := []string{shellVar.String(), "-c", string(arg)}
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900545 cmd := exec.Cmd{
546 Path: cmdline[0],
547 Args: cmdline,
548 Stderr: os.Stderr,
549 }
550 out, err := cmd.Output()
551 if err != nil {
552 Log("$(shell %q) failed: %q", arg, err)
553 }
554
Fumitoshi Ukai5541c7e2015-04-18 22:47:03 +0900555 out = bytes.TrimRight(out, "\n")
556 out = bytes.Replace(out, []byte{'\n'}, []byte{' '}, -1)
557 w.Write(out)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900558}
559
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900560// https://www.gnu.org/software/make/manual/html_node/Call-Function.html#Call-Function
561type funcCall struct{ fclosure }
562
563func (f *funcCall) Arity() int { return 0 }
564
565func (f *funcCall) Eval(w io.Writer, ev *Evaluator) {
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900566 variable := ev.Value(f.args[1])
567 Log("call %q variable %q", f.args[1], variable)
568 v := ev.LookupVar(string(variable))
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900569 // Evalualte all arguments first before we modify the table.
Shinichiro Hamaji39728f12015-04-11 20:12:23 +0900570 var args []tmpval
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900571 // $0 is variable.
572 args = append(args, tmpval(variable))
573 // TODO(ukai): If variable is the name of a built-in function,
574 // the built-in function is always invoked (even if a make variable
575 // by that name also exists).
576
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900577 for i, arg := range f.args[2:] {
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900578 // f.args[2] will be $1.
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900579 args = append(args, tmpval(ev.Value(arg)))
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900580 Log("call $%d: %q=>%q", i+1, arg, args[i+1])
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900581 }
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900582 oldParams := ev.paramVars
583 ev.paramVars = args
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900584
Fumitoshi Ukai9b10ecf2015-04-15 17:45:50 +0900585 var restores []func()
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900586 for i, arg := range args {
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900587 name := fmt.Sprintf("%d", i)
Fumitoshi Ukai9b10ecf2015-04-15 17:45:50 +0900588 restores = append(restores, ev.outVars.save(name))
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900589 ev.outVars.Assign(name, SimpleVar{
590 value: arg,
591 origin: "automatic", // ??
592 })
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900593 }
594
595 var buf bytes.Buffer
Fumitoshi Ukaie27a25d2015-04-18 00:31:01 +0900596 if katiLogFlag {
597 w = io.MultiWriter(w, &buf)
598 }
599 v.Eval(w, ev)
Fumitoshi Ukai9b10ecf2015-04-15 17:45:50 +0900600 for _, restore := range restores {
601 restore()
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900602 }
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900603 ev.paramVars = oldParams
604 Log("call %q variable %q return %q", f.args[1], variable, buf.Bytes())
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900605}
606
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900607// http://www.gnu.org/software/make/manual/make.html#Value-Function
608type funcValue struct{ fclosure }
609
610func (f *funcValue) Arity() int { return 1 }
611func (f *funcValue) Eval(w io.Writer, ev *Evaluator) {
612 assertArity("value", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900613 v := ev.LookupVar(f.args[1].String())
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900614 w.Write([]byte(v.String()))
615}
616
617// http://www.gnu.org/software/make/manual/make.html#Eval-Function
618type funcEval struct{ fclosure }
619
620func (f *funcEval) Arity() int { return 1 }
621func (f *funcEval) Eval(w io.Writer, ev *Evaluator) {
622 assertArity("eval", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900623 s := ev.Value(f.args[1])
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900624 mk, err := ParseMakefileBytes(s, ev.filename, ev.lineno)
625 if err != nil {
626 panic(err)
627 }
628
629 for _, stmt := range mk.stmts {
630 ev.eval(stmt)
631 }
632}
633
Fumitoshi Ukai9f6b6352015-04-16 16:25:09 +0900634func (f *funcEval) Compact() Value {
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900635 if len(f.args)-1 < 1 {
636 return f
637 }
Shinichiro Hamaji74536e62015-04-21 15:40:34 +0900638 switch f.args[1].(type) {
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900639 case literal, tmpval:
640 default:
Shinichiro Hamaji74536e62015-04-21 15:40:34 +0900641 // TODO(ukai): eval -> varassign. e.g. $(eval foo := $(x))
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900642 return f
643 }
644 arg := f.args[1].String()
645 arg = stripComment(arg)
Shinichiro Hamaji74536e62015-04-21 15:40:34 +0900646 if arg == "" {
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900647 return &funcNop{expr: f.String()}
648 }
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900649 f.args[1] = literal(arg)
Shinichiro Hamaji74536e62015-04-21 15:40:34 +0900650 eq := strings.Index(arg, "=")
651 if eq >= 0 {
652 // TODO(ukai): factor out parse assign?
653 lhs := arg[:eq]
654 op := arg[eq : eq+1]
655 if eq >= 1 && (arg[eq-1] == ':' || arg[eq-1] == '+' || arg[eq-1] == '?') {
656 lhs = arg[:eq-1]
657 op = arg[eq-1 : eq+1]
658 }
659 lhs = strings.TrimSpace(lhs)
660 // no $... in rhs too.
661 rhs := literal(strings.TrimLeft(arg[eq+1:], " \t"))
662 if strings.IndexAny(lhs, ":$") >= 0 {
663 // target specific var define? or need eval.
664 return f
665 }
666 if strings.Index(string(rhs), "$") >= 0 {
667 // need eval. e.g. rhs was "$$(foo)", it is literal
668 // "$(foo)", so need eval at runtime.
669 // TODO(ukai): make it funcEvalAssign.
670 return f
671 }
Fumitoshi Ukai150c8612015-04-16 15:35:44 +0900672 return &funcEvalAssign{
673 lhs: lhs,
674 op: op,
675 rhs: rhs,
676 }
677 }
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900678 return f
679}
680
681func stripComment(arg string) string {
682 for {
683 i := strings.Index(arg, "#")
684 if i < 0 {
685 return arg
686 }
687 eol := strings.Index(arg[i:], "\n")
688 if eol < 0 {
689 return arg[:i]
690 }
691 arg = arg[:i] + arg[eol+1:]
692 }
693}
694
695type funcNop struct{ expr string }
696
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900697func (f *funcNop) String() string { return f.expr }
698func (f *funcNop) Eval(io.Writer, *Evaluator) {}
699
Fumitoshi Ukai150c8612015-04-16 15:35:44 +0900700type funcEvalAssign struct {
701 lhs string
702 op string
703 rhs Value
704}
705
Fumitoshi Ukai150c8612015-04-16 15:35:44 +0900706func (f *funcEvalAssign) String() string {
707 return fmt.Sprintf("$(eval %s %s %s)", f.lhs, f.op, f.rhs)
708}
709
710func (f *funcEvalAssign) Eval(w io.Writer, ev *Evaluator) {
711 rhs := ev.Value(f.rhs)
712 var rvalue Var
713 switch f.op {
714 case ":=":
Fumitoshi Ukaifa5e9222015-04-17 11:45:20 +0900715 expr, _, err := parseExpr(rhs, nil)
716 if err != nil {
717 panic(fmt.Sprintf("eval assign error: %q: %v", f.String(), err))
718 }
719 rvalue = SimpleVar{value: tmpval(ev.Value(expr)), origin: "file"}
Fumitoshi Ukai150c8612015-04-16 15:35:44 +0900720 case "=":
721 rvalue = RecursiveVar{expr: tmpval(rhs), origin: "file"}
722 case "+=":
723 prev := ev.LookupVar(f.lhs)
Shinichiro Hamaji74536e62015-04-21 15:40:34 +0900724 if !prev.IsDefined() {
Fumitoshi Ukai150c8612015-04-16 15:35:44 +0900725 rvalue = prev.Append(ev, string(rhs))
726 } else {
727 rvalue = RecursiveVar{expr: tmpval(rhs), origin: "file"}
728 }
729 case "?=":
730 prev := ev.LookupVar(f.lhs)
731 if prev.IsDefined() {
732 return
733 }
734 rvalue = RecursiveVar{expr: tmpval(rhs), origin: "file"}
735 }
736 ev.outVars.Assign(f.lhs, rvalue)
737}
738
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +0900739// http://www.gnu.org/software/make/manual/make.html#Origin-Function
740type funcOrigin struct{ fclosure }
741
742func (f *funcOrigin) Arity() int { return 1 }
743func (f *funcOrigin) Eval(w io.Writer, ev *Evaluator) {
744 assertArity("origin", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900745 v := ev.LookupVar(f.args[1].String())
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +0900746 w.Write([]byte(v.Origin()))
747}
748
749// https://www.gnu.org/software/make/manual/html_node/Flavor-Function.html#Flavor-Function
750type funcFlavor struct{ fclosure }
751
752func (f *funcFlavor) Arity() int { return 1 }
753func (f *funcFlavor) Eval(w io.Writer, ev *Evaluator) {
754 assertArity("flavor", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900755 v := ev.LookupVar(f.args[1].String())
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +0900756 w.Write([]byte(v.Flavor()))
757}
758
759// http://www.gnu.org/software/make/manual/make.html#Make-Control-Functions
760type funcInfo struct{ fclosure }
761
762func (f *funcInfo) Arity() int { return 1 }
763func (f *funcInfo) Eval(w io.Writer, ev *Evaluator) {
764 assertArity("info", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900765 arg := ev.Value(f.args[1])
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +0900766 fmt.Printf("%s\n", arg)
767}
768
769type funcWarning struct{ fclosure }
770
771func (f *funcWarning) Arity() int { return 1 }
772func (f *funcWarning) Eval(w io.Writer, ev *Evaluator) {
773 assertArity("warning", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900774 arg := ev.Value(f.args[1])
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +0900775 fmt.Printf("%s:%d: %s\n", ev.filename, ev.lineno, arg)
776}
777
778type funcError struct{ fclosure }
779
780func (f *funcError) Arity() int { return 1 }
781func (f *funcError) Eval(w io.Writer, ev *Evaluator) {
782 assertArity("error", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900783 arg := ev.Value(f.args[1])
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +0900784 Error(ev.filename, ev.lineno, "*** %s.", arg)
785}
786
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900787// http://www.gnu.org/software/make/manual/make.html#Foreach-Function
788type funcForeach struct{ fclosure }
789
790func (f *funcForeach) Arity() int { return 3 }
791
792func (f *funcForeach) Eval(w io.Writer, ev *Evaluator) {
793 assertArity("foreach", 3, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900794 varname := string(ev.Value(f.args[1]))
795 list := ev.Values(f.args[2])
796 text := f.args[3]
Fumitoshi Ukai9b10ecf2015-04-15 17:45:50 +0900797 restore := ev.outVars.save(varname)
798 defer restore()
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900799 space := false
800 for _, word := range list {
801 ev.outVars.Assign(varname,
802 SimpleVar{
Shinichiro Hamaji39728f12015-04-11 20:12:23 +0900803 value: word,
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900804 origin: "automatic",
805 })
806 if space {
807 w.Write([]byte{' '})
808 }
Fumitoshi Ukaie27a25d2015-04-18 00:31:01 +0900809 text.Eval(w, ev)
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900810 space = true
811 }
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900812}