blob: 761527ff1ef526e3336f24994485701016f89ae6 [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
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090015// TODO(ukai): move in var.go?
Shinichiro Hamajicc919ae2015-04-09 17:23:30 +090016type oldVar struct {
17 name string
18 value Var
19}
20
21func newOldVar(ev *Evaluator, name string) oldVar {
22 return oldVar{
23 name: name,
24 value: ev.outVars.Lookup(name),
25 }
26}
27
28func (old oldVar) restore(ev *Evaluator) {
29 if old.value.IsDefined() {
30 ev.outVars.Assign(old.name, old.value)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090031 return
Shinichiro Hamajicc919ae2015-04-09 17:23:30 +090032 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090033 delete(ev.outVars, old.name)
Shinichiro Hamajicc919ae2015-04-09 17:23:30 +090034}
35
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090036// Func is a make function.
37// http://www.gnu.org/software/make/manual/make.html#Functions
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090038
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090039// Func is make builtin function.
40type Func interface {
41 // Arity is max function's arity.
42 // ',' will not be handled as argument separator more than arity.
43 // 0 means varargs.
44 Arity() int
45
46 // AddArg adds value as an argument.
47 AddArg(Value)
48
Fumitoshi Ukaiebf945c2015-04-10 17:30:04 +090049 // SetString sets original string of the func.
50 SetString(string)
51
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090052 Value
53}
54
55var (
56 funcMap = map[string]func() Func{
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +090057 "patsubst": func() Func { return &funcPatsubst{} },
58 "strip": func() Func { return &funcStrip{} },
59 "subst": func() Func { return &funcSubst{} },
60 "findstring": func() Func { return &funcFindstring{} },
61 "filter": func() Func { return &funcFilter{} },
62 "filter-out": func() Func { return &funcFilterOut{} },
63 "sort": func() Func { return &funcSort{} },
64 "word": func() Func { return &funcWord{} },
65 "wordlist": func() Func { return &funcWordlist{} },
66 "words": func() Func { return &funcWords{} },
67 "firstword": func() Func { return &funcFirstword{} },
68 "lastword": func() Func { return &funcLastword{} },
69
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +090070 "join": func() Func { return &funcJoin{} },
71 "wildcard": func() Func { return &funcWildcard{} },
72 "dir": func() Func { return &funcDir{} },
73 "notdir": func() Func { return &funcNotdir{} },
74 "suffix": func() Func { return &funcSuffix{} },
75 "basename": func() Func { return &funcBasename{} },
76 "addsuffix": func() Func { return &funcAddsuffix{} },
77 "addprefix": func() Func { return &funcAddprefix{} },
78 "realpath": func() Func { return &funcRealpath{} },
79 "abspath": func() Func { return &funcAbspath{} },
80
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +090081 "if": func() Func { return &funcIf{} },
82 "and": func() Func { return &funcAnd{} },
83 "or": func() Func { return &funcOr{} },
84
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +090085 "value": func() Func { return &funcValue{} },
86
87 "eval": func() Func { return &funcEval{} },
88
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +090089 "shell": func() Func { return &funcShell{} },
90 "call": func() Func { return &funcCall{} },
91 "foreach": func() Func { return &funcForeach{} },
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +090092
93 "origin": func() Func { return &funcOrigin{} },
94 "flavor": func() Func { return &funcFlavor{} },
95 "info": func() Func { return &funcInfo{} },
96 "warning": func() Func { return &funcWarning{} },
97 "error": func() Func { return &funcError{} },
Fumitoshi Ukai0b5e18b2015-04-03 22:57:17 +090098 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090099)
100
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900101func assertArity(name string, req, n int) {
102 if n < req {
103 panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `%s'.", n, name))
104 }
105}
106
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900107// A space separated values writer.
108type ssvWriter struct {
109 w io.Writer
110 needsSpace bool
111}
112
113func (sw *ssvWriter) Write(b []byte) {
114 if sw.needsSpace {
115 sw.w.Write([]byte{' '})
116 }
117 sw.needsSpace = true
118 sw.w.Write(b)
119}
120
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900121func (sw *ssvWriter) WriteString(s string) {
122 // TODO: Ineffcient. Nice if we can remove the cast.
123 sw.Write([]byte(s))
124}
125
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900126func numericValueForFunc(ev *Evaluator, v Value, funcName string, nth string) int {
127 a := bytes.TrimSpace(ev.Value(v))
128 n, err := strconv.Atoi(string(a))
129 if err != nil || n < 0 {
130 Error(ev.filename, ev.lineno, `*** non-numeric %s argument to "%s" function: "%s".`, nth, funcName, a)
131 }
132 return n
133}
134
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900135type fclosure struct {
136 args []Value
Fumitoshi Ukaiebf945c2015-04-10 17:30:04 +0900137 expr string
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900138}
139
140func (c *fclosure) AddArg(v Value) {
141 c.args = append(c.args, v)
Fumitoshi Ukai0b5e18b2015-04-03 22:57:17 +0900142}
143
Fumitoshi Ukaiebf945c2015-04-10 17:30:04 +0900144func (c *fclosure) SetString(s string) { c.expr = s }
145func (c *fclosure) String() string { return c.expr }
Fumitoshi Ukai78781132015-04-10 17:08:40 +0900146
Shinichiro Hamaji4125cf42015-04-03 11:42:28 +0900147// http://www.gnu.org/software/make/manual/make.html#Text-Functions
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900148type funcSubst struct{ fclosure }
149
150func (f *funcSubst) Arity() int { return 3 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900151func (f *funcSubst) Eval(w io.Writer, ev *Evaluator) {
152 assertArity("subst", 3, len(f.args))
153 from := ev.Value(f.args[0])
154 to := ev.Value(f.args[1])
155 text := ev.Value(f.args[2])
Fumitoshi Ukaibb79a9d2015-04-02 12:46:54 +0900156 Log("subst from:%q to:%q text:%q", from, to, text)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900157 w.Write(bytes.Replace(text, from, to, -1))
158}
159
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900160type funcPatsubst struct{ fclosure }
161
162func (f *funcPatsubst) Arity() int { return 3 }
163func (f *funcPatsubst) Eval(w io.Writer, ev *Evaluator) {
164 assertArity("patsubst", 3, len(f.args))
165 pat := ev.Value(f.args[0])
166 repl := ev.Value(f.args[1])
167 texts := splitSpacesBytes(ev.Value(f.args[2]))
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900168 sw := ssvWriter{w: w}
169 for _, text := range texts {
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900170 t := substPatternBytes(pat, repl, text)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900171 sw.Write(t)
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900172 }
173}
174
175type funcStrip struct{ fclosure }
176
177func (f *funcStrip) Arity() int { return 1 }
178func (f *funcStrip) Eval(w io.Writer, ev *Evaluator) {
179 assertArity("strip", 1, len(f.args))
180 text := ev.Value(f.args[0])
181 w.Write(bytes.TrimSpace(text))
182}
183
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900184type funcFindstring struct{ fclosure }
185
186func (f *funcFindstring) Arity() int { return 2 }
187func (f *funcFindstring) Eval(w io.Writer, ev *Evaluator) {
188 assertArity("findstring", 2, len(f.args))
189 find := ev.Value(f.args[0])
190 text := ev.Value(f.args[1])
191 if bytes.Index(text, find) >= 0 {
192 w.Write(find)
193 }
194}
195
196type funcFilter struct{ fclosure }
197
198func (f *funcFilter) Arity() int { return 2 }
199func (f *funcFilter) Eval(w io.Writer, ev *Evaluator) {
200 assertArity("filter", 2, len(f.args))
201 patterns := splitSpacesBytes(ev.Value(f.args[0]))
202 texts := splitSpacesBytes(ev.Value(f.args[1]))
203 sw := ssvWriter{w: w}
204 for _, text := range texts {
205 for _, pat := range patterns {
206 if matchPatternBytes(pat, text) {
207 sw.Write(text)
208 }
209 }
210 }
211}
212
213type funcFilterOut struct{ fclosure }
214
215func (f *funcFilterOut) Arity() int { return 2 }
216func (f *funcFilterOut) Eval(w io.Writer, ev *Evaluator) {
217 assertArity("filter-out", 2, len(f.args))
218 patterns := splitSpacesBytes(ev.Value(f.args[0]))
219 texts := splitSpacesBytes(ev.Value(f.args[1]))
220 sw := ssvWriter{w: w}
221Loop:
222 for _, text := range texts {
223 for _, pat := range patterns {
224 if matchPatternBytes(pat, text) {
225 continue Loop
226 }
227 }
228 sw.Write(text)
229 }
230}
231
232type funcSort struct{ fclosure }
233
234func (f *funcSort) Arity() int { return 1 }
235func (f *funcSort) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900236 assertArity("sort", 1, len(f.args))
237 toks := splitSpaces(string(ev.Value(f.args[0])))
238 sort.Strings(toks)
239
240 // Remove duplicate words.
241 var prev string
242 sw := ssvWriter{w: w}
243 for _, tok := range toks {
244 if prev != tok {
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900245 sw.WriteString(tok)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900246 prev = tok
247 }
248 }
249}
250
251type funcWord struct{ fclosure }
252
253func (f *funcWord) Arity() int { return 2 }
254func (f *funcWord) Eval(w io.Writer, ev *Evaluator) {
255 assertArity("word", 2, len(f.args))
256 index := numericValueForFunc(ev, f.args[0], "word", "first")
257 if index == 0 {
258 Error(ev.filename, ev.lineno, `*** first argument to "word" function must be greater than 0.`)
259 }
260 toks := splitSpacesBytes(ev.Value(f.args[1]))
261 if index-1 >= len(toks) {
262 return
263 }
264 w.Write(toks[index-1])
265}
266
267type funcWordlist struct{ fclosure }
268
269func (f *funcWordlist) Arity() int { return 3 }
270func (f *funcWordlist) Eval(w io.Writer, ev *Evaluator) {
271 assertArity("wordlist", 3, len(f.args))
272 si := numericValueForFunc(ev, f.args[0], "wordlist", "first")
273 if si == 0 {
274 Error(ev.filename, ev.lineno, `*** invalid first argument to "wordlist" function: %s`, f.args[0])
275 }
276 ei := numericValueForFunc(ev, f.args[1], "wordlist", "second")
277 if ei == 0 {
278 Error(ev.filename, ev.lineno, `*** invalid second argument to "wordlist" function: %s`, f.args[1])
279 }
280
281 toks := splitSpacesBytes(ev.Value(f.args[2]))
282 if si-1 >= len(toks) {
283 return
284 }
285 if ei-1 >= len(toks) {
286 ei = len(toks)
287 }
288
289 sw := ssvWriter{w: w}
290 for _, t := range toks[si-1 : ei] {
291 sw.Write(t)
292 }
293}
294
295type funcWords struct{ fclosure }
296
297func (f *funcWords) Arity() int { return 1 }
298func (f *funcWords) Eval(w io.Writer, ev *Evaluator) {
299 assertArity("words", 1, len(f.args))
300 toks := splitSpacesBytes(ev.Value(f.args[0]))
301 w.Write([]byte(strconv.Itoa(len(toks))))
302}
303
304type funcFirstword struct{ fclosure }
305
306func (f *funcFirstword) Arity() int { return 1 }
307func (f *funcFirstword) Eval(w io.Writer, ev *Evaluator) {
308 assertArity("firstword", 1, len(f.args))
309 toks := splitSpacesBytes(ev.Value(f.args[0]))
310 if len(toks) == 0 {
311 return
312 }
313 w.Write(toks[0])
314}
315
316type funcLastword struct{ fclosure }
317
318func (f *funcLastword) Arity() int { return 1 }
319func (f *funcLastword) Eval(w io.Writer, ev *Evaluator) {
320 assertArity("lastword", 1, len(f.args))
321 toks := splitSpacesBytes(ev.Value(f.args[0]))
322 if len(toks) == 0 {
323 return
324 }
325 w.Write(toks[len(toks)-1])
326}
327
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900328// https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html#File-Name-Functions
329
330type funcJoin struct{ fclosure }
331
332func (f *funcJoin) Arity() int { return 2 }
333func (f *funcJoin) Eval(w io.Writer, ev *Evaluator) {
334 assertArity("join", 2, len(f.args))
335 list1 := splitSpacesBytes(ev.Value(f.args[0]))
336 list2 := splitSpacesBytes(ev.Value(f.args[1]))
337 sw := ssvWriter{w: w}
338 for i, v := range list1 {
339 if i < len(list2) {
340 sw.Write(v)
341 // Use |w| not to append extra ' '.
342 w.Write(list2[i])
343 continue
344 }
345 sw.Write(v)
346 }
347 if len(list2) > len(list1) {
348 for _, v := range list2[len(list1):] {
349 sw.Write(v)
350 }
351 }
352}
353
354type funcWildcard struct{ fclosure }
355
356func (f *funcWildcard) Arity() int { return 1 }
357func (f *funcWildcard) Eval(w io.Writer, ev *Evaluator) {
358 assertArity("wildcard", 1, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900359 sw := ssvWriter{w: w}
360 for _, pattern := range splitSpaces(string(ev.Value(f.args[0]))) {
361 files, err := filepath.Glob(pattern)
362 if err != nil {
363 panic(err)
364 }
365 for _, file := range files {
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900366 sw.WriteString(file)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900367 }
368 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900369}
370
371type funcDir struct{ fclosure }
372
373func (f *funcDir) Arity() int { return 1 }
374func (f *funcDir) Eval(w io.Writer, ev *Evaluator) {
375 assertArity("dir", 1, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900376 names := splitSpaces(string(ev.Value(f.args[0])))
377 sw := ssvWriter{w: w}
378 for _, name := range names {
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900379 sw.WriteString(filepath.Dir(name) + string(filepath.Separator))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900380 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900381}
382
383type funcNotdir struct{ fclosure }
384
385func (f *funcNotdir) Arity() int { return 1 }
386func (f *funcNotdir) Eval(w io.Writer, ev *Evaluator) {
387 assertArity("notdir", 1, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900388 names := splitSpaces(string(ev.Value(f.args[0])))
389 sw := ssvWriter{w: w}
390 for _, name := range names {
391 if name == string(filepath.Separator) {
392 sw.Write([]byte{})
393 continue
394 }
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900395 sw.WriteString(filepath.Base(name))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900396 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900397}
398
399type funcSuffix struct{ fclosure }
400
401func (f *funcSuffix) Arity() int { return 1 }
402func (f *funcSuffix) Eval(w io.Writer, ev *Evaluator) {
403 assertArity("suffix", 1, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900404 toks := splitSpaces(string(ev.Value(f.args[0])))
405 sw := ssvWriter{w: w}
406 for _, tok := range toks {
407 e := filepath.Ext(tok)
408 if len(e) > 0 {
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900409 sw.WriteString(e)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900410 }
411 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900412}
413
414type funcBasename struct{ fclosure }
415
416func (f *funcBasename) Arity() int { return 1 }
417func (f *funcBasename) Eval(w io.Writer, ev *Evaluator) {
418 assertArity("basename", 1, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900419 toks := splitSpaces(string(ev.Value(f.args[0])))
420 sw := ssvWriter{w: w}
421 for _, tok := range toks {
422 e := stripExt(tok)
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900423 sw.WriteString(e)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900424 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900425}
426
427type funcAddsuffix struct{ fclosure }
428
429func (f *funcAddsuffix) Arity() int { return 2 }
430func (f *funcAddsuffix) Eval(w io.Writer, ev *Evaluator) {
431 assertArity("addsuffix", 2, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900432 suf := ev.Value(f.args[0])
433 toks := splitSpacesBytes(ev.Value(f.args[1]))
434 sw := ssvWriter{w: w}
435 for _, tok := range toks {
436 sw.Write(tok)
437 // Use |w| not to append extra ' '.
438 w.Write(suf)
439 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900440}
441
442type funcAddprefix struct{ fclosure }
443
444func (f *funcAddprefix) Arity() int { return 2 }
445func (f *funcAddprefix) Eval(w io.Writer, ev *Evaluator) {
446 assertArity("addprefix", 2, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900447 pre := ev.Value(f.args[0])
448 toks := splitSpacesBytes(ev.Value(f.args[1]))
449 sw := ssvWriter{w: w}
450 for _, tok := range toks {
451 sw.Write(pre)
452 // Use |w| not to append extra ' '.
453 w.Write(tok)
454 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900455}
456
457type funcRealpath struct{ fclosure }
458
459func (f *funcRealpath) Arity() int { return 1 }
460func (f *funcRealpath) Eval(w io.Writer, ev *Evaluator) {
461 assertArity("realpath", 1, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900462 names := splitSpaces(string(ev.Value(f.args[0])))
463 sw := ssvWriter{w: w}
464 for _, name := range names {
465 name, err := filepath.Abs(name)
466 if err != nil {
467 Log("abs: %v", err)
468 continue
469 }
470 name, err = filepath.EvalSymlinks(name)
471 if err != nil {
472 Log("realpath: %v", err)
473 continue
474 }
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900475 sw.WriteString(name)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900476 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900477}
478
479type funcAbspath struct{ fclosure }
480
481func (f *funcAbspath) Arity() int { return 1 }
482func (f *funcAbspath) Eval(w io.Writer, ev *Evaluator) {
483 assertArity("abspath", 1, len(f.args))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900484 names := splitSpaces(string(ev.Value(f.args[0])))
485 sw := ssvWriter{w: w}
486 for _, name := range names {
487 name, err := filepath.Abs(name)
488 if err != nil {
489 Log("abs: %v", err)
490 continue
491 }
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900492 sw.WriteString(name)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900493 }
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900494}
495
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900496// http://www.gnu.org/software/make/manual/make.html#Conditional-Functions
497type funcIf struct{ fclosure }
498
499func (f *funcIf) Arity() int { return 3 }
500func (f *funcIf) Eval(w io.Writer, ev *Evaluator) {
501 assertArity("if", 2, len(f.args))
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900502 cond := ev.Value(f.args[0])
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900503 if len(cond) != 0 {
504 w.Write(ev.Value(f.args[1]))
505 return
506 }
507 sw := ssvWriter{w: w}
508 for _, part := range f.args[2:] {
509 sw.Write(ev.Value(part))
510 }
511}
512
513type funcAnd struct{ fclosure }
514
515func (f *funcAnd) Arity() int { return 0 }
516func (f *funcAnd) Eval(w io.Writer, ev *Evaluator) {
517 assertArity("and", 0, len(f.args))
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900518 var cond []byte
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900519 for _, arg := range f.args {
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900520 cond = ev.Value(arg)
521 if len(cond) == 0 {
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900522 return
523 }
524 }
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900525 w.Write(cond)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900526}
527
528type funcOr struct{ fclosure }
529
530func (f *funcOr) Arity() int { return 0 }
531func (f *funcOr) Eval(w io.Writer, ev *Evaluator) {
532 assertArity("or", 0, len(f.args))
533 for _, arg := range f.args {
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900534 cond := ev.Value(arg)
535 if len(cond) != 0 {
536 w.Write(cond)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900537 return
538 }
539 }
540}
541
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900542// http://www.gnu.org/software/make/manual/make.html#Shell-Function
543type funcShell struct{ fclosure }
544
545func (f *funcShell) Arity() int { return 1 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900546
547func (f *funcShell) Eval(w io.Writer, ev *Evaluator) {
548 assertArity("shell", 1, len(f.args))
549 arg := ev.Value(f.args[0])
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900550 shellVar := ev.LookupVar("SHELL")
551 // TODO: Should be Eval, not String.
552 cmdline := []string{shellVar.String(), "-c", string(arg)}
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900553 cmd := exec.Cmd{
554 Path: cmdline[0],
555 Args: cmdline,
556 Stderr: os.Stderr,
557 }
558 out, err := cmd.Output()
559 if err != nil {
560 Log("$(shell %q) failed: %q", arg, err)
561 }
562
563 r := string(out)
564 r = strings.TrimRight(r, "\n")
565 r = strings.Replace(r, "\n", " ", -1)
566 fmt.Fprint(w, r)
567}
568
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900569// https://www.gnu.org/software/make/manual/html_node/Call-Function.html#Call-Function
570type funcCall struct{ fclosure }
571
572func (f *funcCall) Arity() int { return 0 }
573
574func (f *funcCall) Eval(w io.Writer, ev *Evaluator) {
575 variable := string(ev.Value(f.args[0]))
576 v := ev.LookupVar(variable)
577 Log("call variable %q", v)
578 // Evalualte all arguments first before we modify the table.
Shinichiro Hamaji39728f12015-04-11 20:12:23 +0900579 var args []tmpval
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900580 for i, arg := range f.args[1:] {
581 args = append(args, tmpval(ev.Value(arg)))
582 Log("call $%d: %q=>%q", i+1, arg, args[i])
583 }
584
585 var olds []oldVar
586 for i, arg := range args {
587 name := fmt.Sprintf("%d", i+1)
588 olds = append(olds, newOldVar(ev, name))
589 ev.outVars.Assign(name,
590 SimpleVar{
Shinichiro Hamaji39728f12015-04-11 20:12:23 +0900591 value: arg,
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900592 origin: "automatic", // ??
593 })
594 }
595
596 var buf bytes.Buffer
597 v.Eval(&buf, ev)
598 for _, old := range olds {
599 old.restore(ev)
600 }
601 Log("call %q return %q", f.args[0], buf.String())
602 w.Write(buf.Bytes())
603}
604
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900605// http://www.gnu.org/software/make/manual/make.html#Value-Function
606type funcValue struct{ fclosure }
607
608func (f *funcValue) Arity() int { return 1 }
609func (f *funcValue) Eval(w io.Writer, ev *Evaluator) {
610 assertArity("value", 1, len(f.args))
611 v := ev.LookupVar(f.args[0].String())
612 w.Write([]byte(v.String()))
613}
614
615// http://www.gnu.org/software/make/manual/make.html#Eval-Function
616type funcEval struct{ fclosure }
617
618func (f *funcEval) Arity() int { return 1 }
619func (f *funcEval) Eval(w io.Writer, ev *Evaluator) {
620 assertArity("eval", 1, len(f.args))
621 s := ev.Value(f.args[0])
622 if len(s) == 0 || (s[0] == '#' && bytes.IndexByte(s, '\n') < 0) {
623 return
624 }
625 mk, err := ParseMakefileBytes(s, ev.filename, ev.lineno)
626 if err != nil {
627 panic(err)
628 }
629
630 for _, stmt := range mk.stmts {
631 ev.eval(stmt)
632 }
633}
634
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +0900635// http://www.gnu.org/software/make/manual/make.html#Origin-Function
636type funcOrigin struct{ fclosure }
637
638func (f *funcOrigin) Arity() int { return 1 }
639func (f *funcOrigin) Eval(w io.Writer, ev *Evaluator) {
640 assertArity("origin", 1, len(f.args))
641 v := ev.LookupVar(f.args[0].String())
642 w.Write([]byte(v.Origin()))
643}
644
645// https://www.gnu.org/software/make/manual/html_node/Flavor-Function.html#Flavor-Function
646type funcFlavor struct{ fclosure }
647
648func (f *funcFlavor) Arity() int { return 1 }
649func (f *funcFlavor) Eval(w io.Writer, ev *Evaluator) {
650 assertArity("flavor", 1, len(f.args))
651 v := ev.LookupVar(f.args[0].String())
652 w.Write([]byte(v.Flavor()))
653}
654
655// http://www.gnu.org/software/make/manual/make.html#Make-Control-Functions
656type funcInfo struct{ fclosure }
657
658func (f *funcInfo) Arity() int { return 1 }
659func (f *funcInfo) Eval(w io.Writer, ev *Evaluator) {
660 assertArity("info", 1, len(f.args))
661 arg := ev.Value(f.args[0])
662 fmt.Printf("%s\n", arg)
663}
664
665type funcWarning struct{ fclosure }
666
667func (f *funcWarning) Arity() int { return 1 }
668func (f *funcWarning) Eval(w io.Writer, ev *Evaluator) {
669 assertArity("warning", 1, len(f.args))
670 arg := ev.Value(f.args[0])
671 fmt.Printf("%s:%d: %s\n", ev.filename, ev.lineno, arg)
672}
673
674type funcError struct{ fclosure }
675
676func (f *funcError) Arity() int { return 1 }
677func (f *funcError) Eval(w io.Writer, ev *Evaluator) {
678 assertArity("error", 1, len(f.args))
679 arg := ev.Value(f.args[0])
680 Error(ev.filename, ev.lineno, "*** %s.", arg)
681}
682
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900683// http://www.gnu.org/software/make/manual/make.html#Foreach-Function
684type funcForeach struct{ fclosure }
685
686func (f *funcForeach) Arity() int { return 3 }
687
688func (f *funcForeach) Eval(w io.Writer, ev *Evaluator) {
689 assertArity("foreach", 3, len(f.args))
690 varname := string(ev.Value(f.args[0]))
691 list := ev.Values(f.args[1])
692 text := f.args[2]
693 old := newOldVar(ev, varname)
694 space := false
695 for _, word := range list {
696 ev.outVars.Assign(varname,
697 SimpleVar{
Shinichiro Hamaji39728f12015-04-11 20:12:23 +0900698 value: word,
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900699 origin: "automatic",
700 })
701 if space {
702 w.Write([]byte{' '})
703 }
704 w.Write(ev.Value(text))
705 space = true
706 }
707 old.restore(ev)
708}