blob: 121cfa6580befde0d64783d790d70aab6aecce74 [file] [log] [blame]
Shinichiro Hamajib69bf8a2015-06-10 14:52:06 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015package kati
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090016
17import (
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090018 "bytes"
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090019 "fmt"
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090020 "io"
Shinichiro Hamajie7aafb02015-04-09 18:23:46 +090021 "os"
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090022 "os/exec"
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +090023 "path/filepath"
Shinichiro Hamaji13b30d92015-04-03 14:42:21 +090024 "sort"
Shinichiro Hamajie708a9d2015-04-03 14:34:35 +090025 "strconv"
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090026 "strings"
Fumitoshi Ukai586b02a2015-05-08 00:23:10 +090027 "time"
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090028)
29
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +090030// mkFunc is a make function.
Fumitoshi Ukaif2f84562015-03-30 19:47:45 +090031// http://www.gnu.org/software/make/manual/make.html#Functions
Fumitoshi Ukaie520f262015-03-31 17:27:03 +090032
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +090033// mkFunc is make builtin function.
34type mkFunc interface {
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090035 // Arity is max function's arity.
36 // ',' will not be handled as argument separator more than arity.
37 // 0 means varargs.
38 Arity() int
39
40 // AddArg adds value as an argument.
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +090041 // the first argument will be "(funcname", or "{funcname".
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090042 AddArg(Value)
43
44 Value
45}
46
47var (
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +090048 funcMap = map[string]func() mkFunc{
49 "patsubst": func() mkFunc { return &funcPatsubst{} },
50 "strip": func() mkFunc { return &funcStrip{} },
51 "subst": func() mkFunc { return &funcSubst{} },
52 "findstring": func() mkFunc { return &funcFindstring{} },
53 "filter": func() mkFunc { return &funcFilter{} },
54 "filter-out": func() mkFunc { return &funcFilterOut{} },
55 "sort": func() mkFunc { return &funcSort{} },
56 "word": func() mkFunc { return &funcWord{} },
57 "wordlist": func() mkFunc { return &funcWordlist{} },
58 "words": func() mkFunc { return &funcWords{} },
59 "firstword": func() mkFunc { return &funcFirstword{} },
60 "lastword": func() mkFunc { return &funcLastword{} },
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +090061
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +090062 "join": func() mkFunc { return &funcJoin{} },
63 "wildcard": func() mkFunc { return &funcWildcard{} },
64 "dir": func() mkFunc { return &funcDir{} },
65 "notdir": func() mkFunc { return &funcNotdir{} },
66 "suffix": func() mkFunc { return &funcSuffix{} },
67 "basename": func() mkFunc { return &funcBasename{} },
68 "addsuffix": func() mkFunc { return &funcAddsuffix{} },
69 "addprefix": func() mkFunc { return &funcAddprefix{} },
70 "realpath": func() mkFunc { return &funcRealpath{} },
71 "abspath": func() mkFunc { return &funcAbspath{} },
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +090072
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +090073 "if": func() mkFunc { return &funcIf{} },
74 "and": func() mkFunc { return &funcAnd{} },
75 "or": func() mkFunc { return &funcOr{} },
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +090076
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +090077 "value": func() mkFunc { return &funcValue{} },
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +090078
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +090079 "eval": func() mkFunc { return &funcEval{} },
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +090080
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +090081 "shell": func() mkFunc { return &funcShell{} },
82 "call": func() mkFunc { return &funcCall{} },
83 "foreach": func() mkFunc { return &funcForeach{} },
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +090084
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +090085 "origin": func() mkFunc { return &funcOrigin{} },
86 "flavor": func() mkFunc { return &funcFlavor{} },
87 "info": func() mkFunc { return &funcInfo{} },
88 "warning": func() mkFunc { return &funcWarning{} },
89 "error": func() mkFunc { return &funcError{} },
Fumitoshi Ukai0b5e18b2015-04-03 22:57:17 +090090 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090091)
92
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090093func assertArity(name string, req, n int) {
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +090094 if n-1 < req {
95 panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `%s'.", n-1, name))
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +090096 }
97}
98
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +090099func numericValueForFunc(v string) (int, bool) {
100 n, err := strconv.Atoi(v)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900101 if err != nil || n < 0 {
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900102 return n, false
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900103 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900104 return n, true
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900105}
106
Shinichiro Hamajiba6b84d2015-06-03 18:46:13 +0900107func formatCommandOutput(out []byte) []byte {
108 out = bytes.TrimRight(out, "\n")
109 out = bytes.Replace(out, []byte{'\n'}, []byte{' '}, -1)
110 return out
111}
112
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900113type fclosure struct {
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900114 // args[0] is "(funcname", or "{funcname".
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900115 args []Value
116}
117
118func (c *fclosure) AddArg(v Value) {
119 c.args = append(c.args, v)
Fumitoshi Ukai0b5e18b2015-04-03 22:57:17 +0900120}
121
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900122func (c *fclosure) String() string {
123 if len(c.args) == 0 {
124 panic("no args in func")
125 }
126 arg0 := c.args[0].String()
127 if arg0 == "" {
128 panic(fmt.Errorf("wrong format of arg0: %q", arg0))
129 }
130 cp := closeParen(arg0[0])
131 if cp == 0 {
132 panic(fmt.Errorf("wrong format of arg0: %q", arg0))
133 }
134 var args []string
135 for _, arg := range c.args[1:] {
136 args = append(args, arg.String())
137 }
138 return fmt.Sprintf("$%s %s%c", arg0, strings.Join(args, ","), cp)
139}
Fumitoshi Ukai78781132015-04-10 17:08:40 +0900140
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +0900141func (c *fclosure) serialize() serializableVar {
142 r := serializableVar{Type: "func"}
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900143 for _, a := range c.args {
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +0900144 r.Children = append(r.Children, a.serialize())
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900145 }
146 return r
147}
148
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +0900149func (c *fclosure) dump(w io.Writer) {
Fumitoshi Ukaia78fce02015-06-25 12:29:09 +0900150 dumpByte(w, valueTypeFunc)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900151 for _, a := range c.args {
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +0900152 a.dump(w)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900153 }
154}
155
Shinichiro Hamaji4125cf42015-04-03 11:42:28 +0900156// http://www.gnu.org/software/make/manual/make.html#Text-Functions
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900157type funcSubst struct{ fclosure }
158
159func (f *funcSubst) Arity() int { return 3 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900160func (f *funcSubst) Eval(w io.Writer, ev *Evaluator) {
161 assertArity("subst", 3, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900162 abuf := newBuf()
163 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900164 t := time.Now()
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900165 from := fargs[0]
166 to := fargs[1]
167 text := fargs[2]
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900168 Logf("subst from:%q to:%q text:%q", from, to, text)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900169 w.Write(bytes.Replace(text, from, to, -1))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900170 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900171 stats.add("funcbody", "subst", t)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900172}
173
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900174type funcPatsubst struct{ fclosure }
175
176func (f *funcPatsubst) Arity() int { return 3 }
177func (f *funcPatsubst) Eval(w io.Writer, ev *Evaluator) {
178 assertArity("patsubst", 3, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900179 abuf := newBuf()
180 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900181 t := time.Now()
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900182 pat := fargs[0]
183 repl := fargs[1]
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900184 ws := newWordScanner(fargs[2])
Fumitoshi Ukai77411fb2015-06-19 15:46:21 +0900185 space := false
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900186 for ws.Scan() {
Fumitoshi Ukai77411fb2015-06-19 15:46:21 +0900187 if space {
188 writeByte(w, ' ')
189 }
190 pre, subst, post := substPatternBytes(pat, repl, ws.Bytes())
191 w.Write(pre)
192 if subst != nil {
193 w.Write(subst)
194 w.Write(post)
195 }
196 space = true
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900197 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900198 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900199 stats.add("funcbody", "patsubst", t)
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900200}
201
202type funcStrip struct{ fclosure }
203
204func (f *funcStrip) Arity() int { return 1 }
205func (f *funcStrip) Eval(w io.Writer, ev *Evaluator) {
206 assertArity("strip", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900207 abuf := newBuf()
208 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900209 t := time.Now()
Shinichiro Hamajib978e112015-06-05 11:02:45 +0900210 ws := newWordScanner(abuf.Bytes())
Fumitoshi Ukaia44b7662015-06-19 11:07:07 +0900211 space := false
Shinichiro Hamajib978e112015-06-05 11:02:45 +0900212 for ws.Scan() {
Fumitoshi Ukaia44b7662015-06-19 11:07:07 +0900213 if space {
214 writeByte(w, ' ')
215 }
216 w.Write(ws.Bytes())
217 space = true
Shinichiro Hamajib978e112015-06-05 11:02:45 +0900218 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900219 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900220 stats.add("funcbody", "strip", t)
Shinichiro Hamaji98e910d2015-04-11 10:38:44 +0900221}
222
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900223type funcFindstring struct{ fclosure }
224
225func (f *funcFindstring) Arity() int { return 2 }
226func (f *funcFindstring) Eval(w io.Writer, ev *Evaluator) {
227 assertArity("findstring", 2, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900228 abuf := newBuf()
229 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900230 t := time.Now()
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900231 find := fargs[0]
232 text := fargs[1]
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900233 if bytes.Index(text, find) >= 0 {
234 w.Write(find)
235 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900236 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900237 stats.add("funcbody", "findstring", t)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900238}
239
240type funcFilter struct{ fclosure }
241
242func (f *funcFilter) Arity() int { return 2 }
243func (f *funcFilter) Eval(w io.Writer, ev *Evaluator) {
244 assertArity("filter", 2, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900245 abuf := newBuf()
246 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900247 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900248 var patterns [][]byte
249 ws := newWordScanner(fargs[0])
250 for ws.Scan() {
251 patterns = append(patterns, ws.Bytes())
252 }
253 ws = newWordScanner(fargs[1])
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900254 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900255 for ws.Scan() {
256 text := ws.Bytes()
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900257 for _, pat := range patterns {
258 if matchPatternBytes(pat, text) {
259 sw.Write(text)
260 }
261 }
262 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900263 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900264 stats.add("funcbody", "filter", t)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900265}
266
267type funcFilterOut struct{ fclosure }
268
269func (f *funcFilterOut) Arity() int { return 2 }
270func (f *funcFilterOut) Eval(w io.Writer, ev *Evaluator) {
271 assertArity("filter-out", 2, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900272 abuf := newBuf()
273 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900274 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900275 var patterns [][]byte
276 ws := newWordScanner(fargs[0])
277 for ws.Scan() {
278 patterns = append(patterns, ws.Bytes())
279 }
280 ws = newWordScanner(fargs[1])
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900281 sw := ssvWriter{w: w}
282Loop:
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900283 for ws.Scan() {
284 text := ws.Bytes()
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900285 for _, pat := range patterns {
286 if matchPatternBytes(pat, text) {
287 continue Loop
288 }
289 }
290 sw.Write(text)
291 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900292 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900293 stats.add("funcbody", "filter-out", t)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900294}
295
296type funcSort struct{ fclosure }
297
298func (f *funcSort) Arity() int { return 1 }
299func (f *funcSort) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900300 assertArity("sort", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900301 abuf := newBuf()
302 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900303 t := time.Now()
Fumitoshi Ukai79cfbab2015-06-18 23:28:26 +0900304 ws := newWordScanner(abuf.Bytes())
305 var toks []string
306 for ws.Scan() {
307 toks = append(toks, string(ws.Bytes()))
308 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900309 freeBuf(abuf)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900310 sort.Strings(toks)
311
312 // Remove duplicate words.
313 var prev string
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900314 for _, tok := range toks {
Fumitoshi Ukaice14acb2015-06-19 13:54:53 +0900315 if prev == tok {
316 continue
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900317 }
Fumitoshi Ukaice14acb2015-06-19 13:54:53 +0900318 if prev != "" {
319 writeByte(w, ' ')
320 }
321 io.WriteString(w, tok)
322 prev = tok
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900323 }
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900324 stats.add("funcbody", "sort", t)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900325}
326
327type funcWord struct{ fclosure }
328
329func (f *funcWord) Arity() int { return 2 }
330func (f *funcWord) Eval(w io.Writer, ev *Evaluator) {
331 assertArity("word", 2, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900332 abuf := newBuf()
333 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900334 t := time.Now()
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900335 v := string(trimSpaceBytes(fargs[0]))
336 index, ok := numericValueForFunc(v)
337 if !ok {
338 Error(ev.filename, ev.lineno, `*** non-numeric first argument to "word" function: %q.`, v)
339 }
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900340 if index == 0 {
341 Error(ev.filename, ev.lineno, `*** first argument to "word" function must be greater than 0.`)
342 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900343 ws := newWordScanner(fargs[1])
344 for ws.Scan() {
345 index--
346 if index == 0 {
347 w.Write(ws.Bytes())
348 break
349 }
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900350 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900351 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900352 stats.add("funcbody", "word", t)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900353}
354
355type funcWordlist struct{ fclosure }
356
357func (f *funcWordlist) Arity() int { return 3 }
358func (f *funcWordlist) Eval(w io.Writer, ev *Evaluator) {
359 assertArity("wordlist", 3, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900360 abuf := newBuf()
361 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900362 t := time.Now()
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900363 v := string(trimSpaceBytes(fargs[0]))
364 si, ok := numericValueForFunc(v)
365 if !ok {
366 Error(ev.filename, ev.lineno, `*** non-numeric first argument to "wordlist" function: %q.`, v)
367 }
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900368 if si == 0 {
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900369 Error(ev.filename, ev.lineno, `*** invalid first argument to "wordlist" function: %s`, f.args[1])
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900370 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900371 v = string(trimSpaceBytes(fargs[1]))
372 ei, ok := numericValueForFunc(v)
373 if !ok {
374 Error(ev.filename, ev.lineno, `*** non-numeric second argument to "wordlist" function: %q.`, v)
375 }
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900376
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900377 ws := newWordScanner(fargs[2])
378 i := 0
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900379 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900380 for ws.Scan() {
381 i++
382 if si <= i && i <= ei {
383 sw.Write(ws.Bytes())
384 }
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900385 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900386 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900387 stats.add("funcbody", "wordlist", t)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900388}
389
390type funcWords struct{ fclosure }
391
392func (f *funcWords) Arity() int { return 1 }
393func (f *funcWords) Eval(w io.Writer, ev *Evaluator) {
394 assertArity("words", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900395 abuf := newBuf()
396 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900397 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900398 ws := newWordScanner(abuf.Bytes())
399 n := 0
400 for ws.Scan() {
401 n++
402 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900403 freeBuf(abuf)
Fumitoshi Ukai145598a2015-06-19 10:08:17 +0900404 io.WriteString(w, strconv.Itoa(n))
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900405 stats.add("funcbody", "words", t)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900406}
407
408type funcFirstword struct{ fclosure }
409
410func (f *funcFirstword) Arity() int { return 1 }
411func (f *funcFirstword) Eval(w io.Writer, ev *Evaluator) {
412 assertArity("firstword", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900413 abuf := newBuf()
414 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900415 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900416 ws := newWordScanner(abuf.Bytes())
417 if ws.Scan() {
418 w.Write(ws.Bytes())
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900419 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900420 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900421 stats.add("funcbody", "firstword", t)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900422}
423
424type funcLastword struct{ fclosure }
425
426func (f *funcLastword) Arity() int { return 1 }
427func (f *funcLastword) Eval(w io.Writer, ev *Evaluator) {
428 assertArity("lastword", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900429 abuf := newBuf()
430 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900431 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900432 ws := newWordScanner(abuf.Bytes())
433 var lw []byte
434 for ws.Scan() {
435 lw = ws.Bytes()
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900436 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900437 if lw != nil {
438 w.Write(lw)
439 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900440 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900441 stats.add("funcbody", "lastword", t)
Shinichiro Hamaji05b222d2015-04-11 11:36:37 +0900442}
443
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900444// https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html#File-Name-Functions
445
446type funcJoin struct{ fclosure }
447
448func (f *funcJoin) Arity() int { return 2 }
449func (f *funcJoin) Eval(w io.Writer, ev *Evaluator) {
450 assertArity("join", 2, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900451 abuf := newBuf()
452 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900453 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900454 ws1 := newWordScanner(fargs[0])
455 ws2 := newWordScanner(fargs[1])
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900456 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900457 for {
458 if w1, w2 := ws1.Scan(), ws2.Scan(); !w1 && !w2 {
459 break
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900460 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900461 sw.Write(ws1.Bytes())
462 // Use |w| not to append extra ' '.
463 w.Write(ws2.Bytes())
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900464 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900465 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900466 stats.add("funcbody", "join", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900467}
468
469type funcWildcard struct{ fclosure }
470
471func (f *funcWildcard) Arity() int { return 1 }
472func (f *funcWildcard) Eval(w io.Writer, ev *Evaluator) {
473 assertArity("wildcard", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900474 abuf := newBuf()
475 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900476 te := traceEvent.begin("wildcard", tmpval(abuf.Bytes()), traceEventMain)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900477 if ev.avoidIO && !UseWildcardCache {
Shinichiro Hamaji8b6487f2015-05-26 16:21:47 +0900478 ev.hasIO = true
Fumitoshi Ukai145598a2015-06-19 10:08:17 +0900479 io.WriteString(w, "$(/bin/ls -d ")
Shinichiro Hamaji8b6487f2015-05-26 16:21:47 +0900480 w.Write(abuf.Bytes())
Fumitoshi Ukai145598a2015-06-19 10:08:17 +0900481 io.WriteString(w, " 2> /dev/null)")
Fumitoshi Ukai432a2422015-06-11 15:16:29 +0900482 traceEvent.end(te)
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +0900483 freeBuf(abuf)
Shinichiro Hamaji8b6487f2015-05-26 16:21:47 +0900484 return
485 }
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900486 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900487 ws := newWordScanner(abuf.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900488 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900489 for ws.Scan() {
Shinichiro Hamajiba6b84d2015-06-03 18:46:13 +0900490 pat := string(ws.Bytes())
Fumitoshi Ukai358c68a2015-06-08 13:12:55 +0900491 wildcard(&sw, pat)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900492 }
Fumitoshi Ukai432a2422015-06-11 15:16:29 +0900493 traceEvent.end(te)
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900494 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900495 stats.add("funcbody", "wildcard", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900496}
497
498type funcDir struct{ fclosure }
499
500func (f *funcDir) Arity() int { return 1 }
501func (f *funcDir) Eval(w io.Writer, ev *Evaluator) {
502 assertArity("dir", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900503 abuf := newBuf()
504 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900505 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900506 ws := newWordScanner(abuf.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900507 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900508 for ws.Scan() {
509 name := string(ws.Bytes())
Shinichiro Hamaji37626b62015-04-21 16:59:23 +0900510 if name == "/" {
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900511 sw.WriteString(name)
512 continue
Shinichiro Hamaji37626b62015-04-21 16:59:23 +0900513 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900514 sw.WriteString(filepath.Dir(string(name)) + string(filepath.Separator))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900515 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900516 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900517 stats.add("funcbody", "dir", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900518}
519
520type funcNotdir struct{ fclosure }
521
522func (f *funcNotdir) Arity() int { return 1 }
523func (f *funcNotdir) Eval(w io.Writer, ev *Evaluator) {
524 assertArity("notdir", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900525 abuf := newBuf()
526 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900527 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900528 ws := newWordScanner(abuf.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900529 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900530 for ws.Scan() {
531 name := string(ws.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900532 if name == string(filepath.Separator) {
Fumitoshi Ukai145598a2015-06-19 10:08:17 +0900533 sw.Write([]byte{}) // separator
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900534 continue
535 }
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900536 sw.WriteString(filepath.Base(name))
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900537 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900538 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900539 stats.add("funcbody", "notdir", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900540}
541
542type funcSuffix struct{ fclosure }
543
544func (f *funcSuffix) Arity() int { return 1 }
545func (f *funcSuffix) Eval(w io.Writer, ev *Evaluator) {
546 assertArity("suffix", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900547 abuf := newBuf()
548 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900549 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900550 ws := newWordScanner(abuf.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900551 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900552 for ws.Scan() {
553 tok := string(ws.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900554 e := filepath.Ext(tok)
555 if len(e) > 0 {
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900556 sw.WriteString(e)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900557 }
558 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900559 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900560 stats.add("funcbody", "suffix", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900561}
562
563type funcBasename struct{ fclosure }
564
565func (f *funcBasename) Arity() int { return 1 }
566func (f *funcBasename) Eval(w io.Writer, ev *Evaluator) {
567 assertArity("basename", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900568 abuf := newBuf()
569 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900570 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900571 ws := newWordScanner(abuf.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900572 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900573 for ws.Scan() {
574 tok := string(ws.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900575 e := stripExt(tok)
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900576 sw.WriteString(e)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900577 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900578 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900579 stats.add("funcbody", "basename", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900580}
581
582type funcAddsuffix struct{ fclosure }
583
584func (f *funcAddsuffix) Arity() int { return 2 }
585func (f *funcAddsuffix) Eval(w io.Writer, ev *Evaluator) {
586 assertArity("addsuffix", 2, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900587 abuf := newBuf()
588 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900589 t := time.Now()
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900590 suf := fargs[0]
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900591 ws := newWordScanner(fargs[1])
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900592 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900593 for ws.Scan() {
594 sw.Write(ws.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900595 // Use |w| not to append extra ' '.
596 w.Write(suf)
597 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900598 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900599 stats.add("funcbody", "addsuffix", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900600}
601
602type funcAddprefix struct{ fclosure }
603
604func (f *funcAddprefix) Arity() int { return 2 }
605func (f *funcAddprefix) Eval(w io.Writer, ev *Evaluator) {
606 assertArity("addprefix", 2, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900607 abuf := newBuf()
608 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900609 t := time.Now()
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900610 pre := fargs[0]
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900611 ws := newWordScanner(fargs[1])
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900612 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900613 for ws.Scan() {
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900614 sw.Write(pre)
615 // Use |w| not to append extra ' '.
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900616 w.Write(ws.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900617 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900618 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900619 stats.add("funcbody", "addprefix", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900620}
621
622type funcRealpath struct{ fclosure }
623
624func (f *funcRealpath) Arity() int { return 1 }
625func (f *funcRealpath) Eval(w io.Writer, ev *Evaluator) {
626 assertArity("realpath", 1, len(f.args))
Shinichiro Hamajib41fd502015-04-29 03:34:07 +0900627 if ev.avoidIO {
Fumitoshi Ukai145598a2015-06-19 10:08:17 +0900628 io.WriteString(w, "KATI_TODO(realpath)")
Shinichiro Hamajib41fd502015-04-29 03:34:07 +0900629 ev.hasIO = true
630 return
631 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900632 abuf := newBuf()
633 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900634 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900635 ws := newWordScanner(abuf.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900636 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900637 for ws.Scan() {
638 name := string(ws.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900639 name, err := filepath.Abs(name)
640 if err != nil {
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900641 Logf("abs: %v", err)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900642 continue
643 }
644 name, err = filepath.EvalSymlinks(name)
645 if err != nil {
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900646 Logf("realpath: %v", err)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900647 continue
648 }
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900649 sw.WriteString(name)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900650 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900651 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900652 stats.add("funcbody", "realpath", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900653}
654
655type funcAbspath struct{ fclosure }
656
657func (f *funcAbspath) Arity() int { return 1 }
658func (f *funcAbspath) Eval(w io.Writer, ev *Evaluator) {
659 assertArity("abspath", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900660 abuf := newBuf()
661 f.args[1].Eval(abuf, ev)
Fumitoshi Ukai9e0c68d2015-06-19 13:38:19 +0900662 t := time.Now()
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900663 ws := newWordScanner(abuf.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900664 sw := ssvWriter{w: w}
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900665 for ws.Scan() {
666 name := string(ws.Bytes())
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900667 name, err := filepath.Abs(name)
668 if err != nil {
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900669 Logf("abs: %v", err)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900670 continue
671 }
Shinichiro Hamajia1358912015-04-11 12:16:21 +0900672 sw.WriteString(name)
Shinichiro Hamajiaf61af22015-04-11 12:13:22 +0900673 }
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +0900674 freeBuf(abuf)
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900675 stats.add("funcbody", "abspath", t)
Shinichiro Hamajic20b84d2015-04-11 12:02:51 +0900676}
677
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900678// http://www.gnu.org/software/make/manual/make.html#Conditional-Functions
679type funcIf struct{ fclosure }
680
681func (f *funcIf) Arity() int { return 3 }
682func (f *funcIf) Eval(w io.Writer, ev *Evaluator) {
683 assertArity("if", 2, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900684 abuf := newBuf()
685 f.args[1].Eval(abuf, ev)
686 if len(abuf.Bytes()) != 0 {
687 freeBuf(abuf)
Fumitoshi Ukaie27a25d2015-04-18 00:31:01 +0900688 f.args[2].Eval(w, ev)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900689 return
690 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900691 freeBuf(abuf)
Fumitoshi Ukaie27a25d2015-04-18 00:31:01 +0900692 if len(f.args) > 3 {
693 f.args[3].Eval(w, ev)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900694 }
695}
696
697type funcAnd struct{ fclosure }
698
699func (f *funcAnd) Arity() int { return 0 }
700func (f *funcAnd) Eval(w io.Writer, ev *Evaluator) {
701 assertArity("and", 0, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900702 abuf := newBuf()
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900703 var cond []byte
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900704 for _, arg := range f.args[1:] {
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900705 abuf.Reset()
706 arg.Eval(abuf, ev)
707 cond = abuf.Bytes()
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900708 if len(cond) == 0 {
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900709 freeBuf(abuf)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900710 return
711 }
712 }
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900713 w.Write(cond)
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900714 freeBuf(abuf)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900715}
716
717type funcOr struct{ fclosure }
718
719func (f *funcOr) Arity() int { return 0 }
720func (f *funcOr) Eval(w io.Writer, ev *Evaluator) {
721 assertArity("or", 0, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900722 abuf := newBuf()
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900723 for _, arg := range f.args[1:] {
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900724 abuf.Reset()
725 arg.Eval(abuf, ev)
726 cond := abuf.Bytes()
Shinichiro Hamaji2216dd62015-04-11 13:44:39 +0900727 if len(cond) != 0 {
728 w.Write(cond)
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900729 freeBuf(abuf)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900730 return
731 }
732 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900733 freeBuf(abuf)
Shinichiro Hamaji424baeb2015-04-11 12:35:42 +0900734}
735
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900736// http://www.gnu.org/software/make/manual/make.html#Shell-Function
737type funcShell struct{ fclosure }
738
739func (f *funcShell) Arity() int { return 1 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900740
Shinichiro Hamajic0095e32015-05-27 18:49:06 +0900741// A hack for Android build. We need to evaluate things like $((3+4))
742// when we emit ninja file, because the result of such expressions
743// will be passed to other make functions.
744// TODO: Maybe we should modify Android's Makefile and remove this
745// workaround. It would be also nice if we can detect things like
746// this.
747func hasNoIoInShellScript(s []byte) bool {
748 if len(s) == 0 {
749 return true
750 }
751 if !bytes.HasPrefix(s, []byte("echo $((")) || s[len(s)-1] != ')' {
752 return false
753 }
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900754 Logf("has no IO - evaluate now: %s", s)
Shinichiro Hamajic0095e32015-05-27 18:49:06 +0900755 return true
756}
757
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900758func (f *funcShell) Eval(w io.Writer, ev *Evaluator) {
759 assertArity("shell", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900760 abuf := newBuf()
761 f.args[1].Eval(abuf, ev)
Shinichiro Hamajic0095e32015-05-27 18:49:06 +0900762 if ev.avoidIO && !hasNoIoInShellScript(abuf.Bytes()) {
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900763 te := traceEvent.begin("shell", tmpval(abuf.Bytes()), traceEventMain)
Shinichiro Hamaji8b6487f2015-05-26 16:21:47 +0900764 ev.hasIO = true
Fumitoshi Ukai145598a2015-06-19 10:08:17 +0900765 io.WriteString(w, "$(")
Shinichiro Hamaji8b6487f2015-05-26 16:21:47 +0900766 w.Write(abuf.Bytes())
Fumitoshi Ukai145598a2015-06-19 10:08:17 +0900767 writeByte(w, ')')
Fumitoshi Ukai432a2422015-06-11 15:16:29 +0900768 traceEvent.end(te)
Fumitoshi Ukai6a643232015-06-08 14:11:23 +0900769 freeBuf(abuf)
Shinichiro Hamaji8b6487f2015-05-26 16:21:47 +0900770 return
771 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900772 arg := abuf.String()
773 freeBuf(abuf)
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900774 shellVar := ev.LookupVar("SHELL")
775 // TODO: Should be Eval, not String.
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900776 cmdline := []string{shellVar.String(), "-c", arg}
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900777 if LogFlag {
Fumitoshi Ukai44ae8cf2015-06-24 16:44:15 +0900778 Logf("shell %q", cmdline)
779 }
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900780 cmd := exec.Cmd{
781 Path: cmdline[0],
782 Args: cmdline,
783 Stderr: os.Stderr,
784 }
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900785 te := traceEvent.begin("shell", literal(arg), traceEventMain)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900786 out, err := cmd.Output()
Fumitoshi Ukai9042b992015-06-23 16:10:27 +0900787 shellStats.add(time.Since(te.t))
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900788 if err != nil {
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900789 Logf("$(shell %q) failed: %q", arg, err)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900790 }
Shinichiro Hamajiba6b84d2015-06-03 18:46:13 +0900791 w.Write(formatCommandOutput(out))
Fumitoshi Ukai432a2422015-06-11 15:16:29 +0900792 traceEvent.end(te)
Fumitoshi Ukaib36f3872015-04-10 15:06:38 +0900793}
794
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900795func (f *funcShell) Compact() Value {
796 if len(f.args)-1 < 1 {
797 return f
798 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900799 if !UseFindCache && !UseShellBuiltins {
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900800 return f
801 }
802
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +0900803 var exp expr
Fumitoshi Ukai44ae8cf2015-06-24 16:44:15 +0900804 switch v := f.args[1].(type) {
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +0900805 case expr:
806 exp = v
Fumitoshi Ukai44ae8cf2015-06-24 16:44:15 +0900807 default:
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +0900808 exp = expr{v}
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900809 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900810 if UseShellBuiltins {
Fumitoshi Ukai4a708512015-06-11 17:15:49 +0900811 // hack for android
812 for _, sb := range shBuiltins {
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +0900813 if v, ok := matchExpr(exp, sb.pattern); ok {
814 Logf("shell compact apply %s for %s", sb.name, exp)
Fumitoshi Ukai4a708512015-06-11 17:15:49 +0900815 return sb.compact(f, v)
816 }
Fumitoshi Ukai76b609e2015-06-10 14:56:49 +0900817 }
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +0900818 Logf("shell compact no match: %s", exp)
Fumitoshi Ukai76b609e2015-06-10 14:56:49 +0900819 }
Fumitoshi Ukai106fb792015-06-09 10:37:35 +0900820 return f
821}
822
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900823// https://www.gnu.org/software/make/manual/html_node/Call-Function.html#Call-Function
824type funcCall struct{ fclosure }
825
826func (f *funcCall) Arity() int { return 0 }
827
828func (f *funcCall) Eval(w io.Writer, ev *Evaluator) {
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900829 abuf := newBuf()
830 fargs := ev.args(abuf, f.args[1:]...)
Fumitoshi Ukaif543f4d2015-06-15 15:21:47 +0900831 varname := fargs[0]
832 variable := string(varname)
Fumitoshi Ukai83410132015-06-15 14:50:07 +0900833 te := traceEvent.begin("call", literal(variable), traceEventMain)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900834 if LogFlag {
Fumitoshi Ukai5c04ad82015-06-18 16:14:04 +0900835 Logf("call %q variable %q", f.args[1], variable)
836 }
Fumitoshi Ukaif543f4d2015-06-15 15:21:47 +0900837 v := ev.LookupVar(variable)
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900838 // Evalualte all arguments first before we modify the table.
Shinichiro Hamaji39728f12015-04-11 20:12:23 +0900839 var args []tmpval
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900840 // $0 is variable.
Fumitoshi Ukaif543f4d2015-06-15 15:21:47 +0900841 args = append(args, tmpval(varname))
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900842 // TODO(ukai): If variable is the name of a built-in function,
843 // the built-in function is always invoked (even if a make variable
844 // by that name also exists).
845
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900846 for i, arg := range fargs[1:] {
847 // f.args[2]=>args[1] will be $1.
848 args = append(args, tmpval(arg))
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900849 if LogFlag {
Fumitoshi Ukai5c04ad82015-06-18 16:14:04 +0900850 Logf("call $%d: %q=>%q", i+1, arg, fargs[i+1])
851 }
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900852 }
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900853 oldParams := ev.paramVars
854 ev.paramVars = args
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900855
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900856 var buf bytes.Buffer
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900857 if LogFlag {
Fumitoshi Ukaie27a25d2015-04-18 00:31:01 +0900858 w = io.MultiWriter(w, &buf)
859 }
860 v.Eval(w, ev)
Fumitoshi Ukaif0a2ba72015-04-19 00:02:32 +0900861 ev.paramVars = oldParams
Fumitoshi Ukai72598e72015-06-11 15:53:09 +0900862 traceEvent.end(te)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900863 if LogFlag {
Fumitoshi Ukai5c04ad82015-06-18 16:14:04 +0900864 Logf("call %q variable %q return %q", f.args[1], variable, buf.Bytes())
865 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900866 freeBuf(abuf)
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +0900867}
868
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900869// http://www.gnu.org/software/make/manual/make.html#Value-Function
870type funcValue struct{ fclosure }
871
872func (f *funcValue) Arity() int { return 1 }
873func (f *funcValue) Eval(w io.Writer, ev *Evaluator) {
874 assertArity("value", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +0900875 v := ev.LookupVar(f.args[1].String())
Fumitoshi Ukai145598a2015-06-19 10:08:17 +0900876 io.WriteString(w, v.String())
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900877}
878
879// http://www.gnu.org/software/make/manual/make.html#Eval-Function
880type funcEval struct{ fclosure }
881
882func (f *funcEval) Arity() int { return 1 }
883func (f *funcEval) Eval(w io.Writer, ev *Evaluator) {
884 assertArity("eval", 1, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900885 abuf := newBuf()
886 f.args[1].Eval(abuf, ev)
887 s := abuf.Bytes()
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900888 Logf("eval %q at %s:%d", s, ev.filename, ev.lineno)
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900889 mk, err := ParseMakefileBytes(s, ev.filename, ev.lineno)
890 if err != nil {
891 panic(err)
892 }
893
894 for _, stmt := range mk.stmts {
895 ev.eval(stmt)
896 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900897 freeBuf(abuf)
Shinichiro Hamaji28ea5bc2015-04-11 12:41:08 +0900898}
899
Fumitoshi Ukai9f6b6352015-04-16 16:25:09 +0900900func (f *funcEval) Compact() Value {
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900901 if len(f.args)-1 < 1 {
902 return f
903 }
Fumitoshi Ukaid8cec172015-04-28 00:08:09 +0900904 switch arg := f.args[1].(type) {
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900905 case literal, tmpval:
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +0900906 case expr:
Fumitoshi Ukaid8cec172015-04-28 00:08:09 +0900907 if len(arg) == 1 {
908 return f
909 }
910 switch prefix := arg[0].(type) {
911 case literal, tmpval:
912 lhs, op, rhsprefix, ok := parseAssignLiteral(prefix.String())
913 if ok {
914 // $(eval foo = $(bar))
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +0900915 var rhs expr
Fumitoshi Ukaid8cec172015-04-28 00:08:09 +0900916 if rhsprefix != literal("") {
917 rhs = append(rhs, rhsprefix)
918 }
919 rhs = append(rhs, arg[1:]...)
Fumitoshi Ukai8fabdd02015-06-08 10:27:47 +0900920 Logf("eval assign %#v => lhs:%q op:%q rhs:%#v", f, lhs, op, rhs)
Fumitoshi Ukaid8cec172015-04-28 00:08:09 +0900921 return &funcEvalAssign{
922 lhs: lhs,
923 op: op,
924 rhs: compactExpr(rhs),
925 }
926 }
927 }
928 // TODO(ukai): eval -> varassign. e.g $(eval $(foo) := $(x)).
Fumitoshi Ukai769157a2015-06-02 15:18:53 +0900929 return f
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900930 default:
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900931 return f
932 }
933 arg := f.args[1].String()
934 arg = stripComment(arg)
Fumitoshi Ukaid8cec172015-04-28 00:08:09 +0900935 if arg == "" || strings.TrimSpace(arg) == "" {
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900936 return &funcNop{expr: f.String()}
937 }
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900938 f.args[1] = literal(arg)
Fumitoshi Ukaid8cec172015-04-28 00:08:09 +0900939 lhs, op, rhs, ok := parseAssignLiteral(f.args[1].String())
940 if ok {
Fumitoshi Ukai150c8612015-04-16 15:35:44 +0900941 return &funcEvalAssign{
942 lhs: lhs,
943 op: op,
944 rhs: rhs,
945 }
946 }
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900947 return f
948}
949
950func stripComment(arg string) string {
951 for {
952 i := strings.Index(arg, "#")
953 if i < 0 {
954 return arg
955 }
956 eol := strings.Index(arg[i:], "\n")
957 if eol < 0 {
958 return arg[:i]
959 }
960 arg = arg[:i] + arg[eol+1:]
961 }
962}
963
964type funcNop struct{ expr string }
965
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900966func (f *funcNop) String() string { return f.expr }
967func (f *funcNop) Eval(io.Writer, *Evaluator) {}
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +0900968func (f *funcNop) serialize() serializableVar {
969 return serializableVar{
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900970 Type: "funcNop",
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +0900971 V: f.expr,
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +0900972 }
973}
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +0900974func (f *funcNop) dump(w io.Writer) {
Fumitoshi Ukaia78fce02015-06-25 12:29:09 +0900975 dumpByte(w, valueTypeNop)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +0900976}
Fumitoshi Ukaida7f2552015-04-16 13:33:37 +0900977
Fumitoshi Ukaid8cec172015-04-28 00:08:09 +0900978func parseAssignLiteral(s string) (lhs, op string, rhs Value, ok bool) {
979 eq := strings.Index(s, "=")
980 if eq < 0 {
981 return "", "", nil, false
982 }
983 // TODO(ukai): factor out parse assign?
984 lhs = s[:eq]
985 op = s[eq : eq+1]
986 if eq >= 1 && (s[eq-1] == ':' || s[eq-1] == '+' || s[eq-1] == '?') {
987 lhs = s[:eq-1]
988 op = s[eq-1 : eq+1]
989 }
990 lhs = strings.TrimSpace(lhs)
991 if strings.IndexAny(lhs, ":$") >= 0 {
992 // target specific var, or need eval.
993 return "", "", nil, false
994 }
995 r := strings.TrimLeft(s[eq+1:], " \t")
996 rhs = literal(r)
997 return lhs, op, rhs, true
998}
999
Fumitoshi Ukai150c8612015-04-16 15:35:44 +09001000type funcEvalAssign struct {
1001 lhs string
1002 op string
1003 rhs Value
1004}
1005
Fumitoshi Ukai150c8612015-04-16 15:35:44 +09001006func (f *funcEvalAssign) String() string {
1007 return fmt.Sprintf("$(eval %s %s %s)", f.lhs, f.op, f.rhs)
1008}
1009
1010func (f *funcEvalAssign) Eval(w io.Writer, ev *Evaluator) {
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +09001011 var abuf bytes.Buffer
1012 f.rhs.Eval(&abuf, ev)
1013 rhs := trimLeftSpaceBytes(abuf.Bytes())
Fumitoshi Ukai150c8612015-04-16 15:35:44 +09001014 var rvalue Var
1015 switch f.op {
1016 case ":=":
Fumitoshi Ukaid8cec172015-04-28 00:08:09 +09001017 // TODO(ukai): compute parsed expr in Compact when f.rhs is
1018 // literal? e.g. literal("$(foo)") => varref{literal("foo")}.
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +09001019 exp, _, err := parseExpr(rhs, nil, false)
Fumitoshi Ukaifa5e9222015-04-17 11:45:20 +09001020 if err != nil {
1021 panic(fmt.Sprintf("eval assign error: %q: %v", f.String(), err))
1022 }
Fumitoshi Ukaidd248f22015-06-18 23:04:28 +09001023 vbuf := newBuf()
Fumitoshi Ukai55c8fa92015-06-25 15:56:10 +09001024 exp.Eval(vbuf, ev)
Fumitoshi Ukai7bf992d2015-06-25 12:42:19 +09001025 rvalue = &simpleVar{value: vbuf.String(), origin: "file"}
Fumitoshi Ukaidd248f22015-06-18 23:04:28 +09001026 freeBuf(vbuf)
Fumitoshi Ukai150c8612015-04-16 15:35:44 +09001027 case "=":
Fumitoshi Ukai7bf992d2015-06-25 12:42:19 +09001028 rvalue = &recursiveVar{expr: tmpval(rhs), origin: "file"}
Fumitoshi Ukai150c8612015-04-16 15:35:44 +09001029 case "+=":
1030 prev := ev.LookupVar(f.lhs)
Fumitoshi Ukaid8cec172015-04-28 00:08:09 +09001031 if prev.IsDefined() {
Fumitoshi Ukai150c8612015-04-16 15:35:44 +09001032 rvalue = prev.Append(ev, string(rhs))
1033 } else {
Fumitoshi Ukai7bf992d2015-06-25 12:42:19 +09001034 rvalue = &recursiveVar{expr: tmpval(rhs), origin: "file"}
Fumitoshi Ukai150c8612015-04-16 15:35:44 +09001035 }
1036 case "?=":
1037 prev := ev.LookupVar(f.lhs)
1038 if prev.IsDefined() {
1039 return
1040 }
Fumitoshi Ukai7bf992d2015-06-25 12:42:19 +09001041 rvalue = &recursiveVar{expr: tmpval(rhs), origin: "file"}
Fumitoshi Ukai150c8612015-04-16 15:35:44 +09001042 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +09001043 if LogFlag {
Fumitoshi Ukai5c04ad82015-06-18 16:14:04 +09001044 Logf("Eval ASSIGN: %s=%q (flavor:%q)", f.lhs, rvalue, rvalue.Flavor())
1045 }
Fumitoshi Ukai150c8612015-04-16 15:35:44 +09001046 ev.outVars.Assign(f.lhs, rvalue)
1047}
1048
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +09001049func (f *funcEvalAssign) serialize() serializableVar {
1050 return serializableVar{
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +09001051 Type: "funcEvalAssign",
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +09001052 Children: []serializableVar{
1053 serializableVar{V: f.lhs},
1054 serializableVar{V: f.op},
1055 f.rhs.serialize(),
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +09001056 },
1057 }
1058}
1059
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +09001060func (f *funcEvalAssign) dump(w io.Writer) {
Fumitoshi Ukaia78fce02015-06-25 12:29:09 +09001061 dumpByte(w, valueTypeAssign)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +09001062 dumpString(w, f.lhs)
1063 dumpString(w, f.op)
Fumitoshi Ukaia045ccb2015-06-25 12:57:25 +09001064 f.rhs.dump(w)
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +09001065}
1066
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +09001067// http://www.gnu.org/software/make/manual/make.html#Origin-Function
1068type funcOrigin struct{ fclosure }
1069
1070func (f *funcOrigin) Arity() int { return 1 }
1071func (f *funcOrigin) Eval(w io.Writer, ev *Evaluator) {
1072 assertArity("origin", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +09001073 v := ev.LookupVar(f.args[1].String())
Fumitoshi Ukai145598a2015-06-19 10:08:17 +09001074 io.WriteString(w, v.Origin())
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +09001075}
1076
1077// https://www.gnu.org/software/make/manual/html_node/Flavor-Function.html#Flavor-Function
1078type funcFlavor struct{ fclosure }
1079
1080func (f *funcFlavor) Arity() int { return 1 }
1081func (f *funcFlavor) Eval(w io.Writer, ev *Evaluator) {
1082 assertArity("flavor", 1, len(f.args))
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +09001083 v := ev.LookupVar(f.args[1].String())
Fumitoshi Ukai145598a2015-06-19 10:08:17 +09001084 io.WriteString(w, v.Flavor())
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +09001085}
1086
1087// http://www.gnu.org/software/make/manual/make.html#Make-Control-Functions
1088type funcInfo struct{ fclosure }
1089
1090func (f *funcInfo) Arity() int { return 1 }
1091func (f *funcInfo) Eval(w io.Writer, ev *Evaluator) {
1092 assertArity("info", 1, len(f.args))
Shinichiro Hamajib41fd502015-04-29 03:34:07 +09001093 if ev.avoidIO {
Fumitoshi Ukai145598a2015-06-19 10:08:17 +09001094 io.WriteString(w, "KATI_TODO(info)")
Shinichiro Hamajib41fd502015-04-29 03:34:07 +09001095 ev.hasIO = true
1096 return
1097 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +09001098 abuf := newBuf()
1099 f.args[1].Eval(abuf, ev)
1100 fmt.Printf("%s\n", abuf.String())
1101 freeBuf(abuf)
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +09001102}
1103
1104type funcWarning struct{ fclosure }
1105
1106func (f *funcWarning) Arity() int { return 1 }
1107func (f *funcWarning) Eval(w io.Writer, ev *Evaluator) {
1108 assertArity("warning", 1, len(f.args))
Shinichiro Hamajib41fd502015-04-29 03:34:07 +09001109 if ev.avoidIO {
Fumitoshi Ukai145598a2015-06-19 10:08:17 +09001110 io.WriteString(w, "KATI_TODO(warning)")
Shinichiro Hamajib41fd502015-04-29 03:34:07 +09001111 ev.hasIO = true
1112 return
1113 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +09001114 abuf := newBuf()
1115 f.args[1].Eval(abuf, ev)
1116 fmt.Printf("%s:%d: %s\n", ev.filename, ev.lineno, abuf.String())
1117 freeBuf(abuf)
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +09001118}
1119
1120type funcError struct{ fclosure }
1121
1122func (f *funcError) Arity() int { return 1 }
1123func (f *funcError) Eval(w io.Writer, ev *Evaluator) {
1124 assertArity("error", 1, len(f.args))
Shinichiro Hamajib41fd502015-04-29 03:34:07 +09001125 if ev.avoidIO {
Fumitoshi Ukai145598a2015-06-19 10:08:17 +09001126 io.WriteString(w, "KATI_TODO(error)")
Shinichiro Hamajib41fd502015-04-29 03:34:07 +09001127 ev.hasIO = true
1128 return
1129 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +09001130 abuf := newBuf()
1131 f.args[1].Eval(abuf, ev)
1132 Error(ev.filename, ev.lineno, "*** %s.", abuf.String())
1133 freeBuf(abuf)
Shinichiro Hamaji916f35f2015-04-11 12:46:19 +09001134}
1135
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +09001136// http://www.gnu.org/software/make/manual/make.html#Foreach-Function
1137type funcForeach struct{ fclosure }
1138
1139func (f *funcForeach) Arity() int { return 3 }
1140
1141func (f *funcForeach) Eval(w io.Writer, ev *Evaluator) {
1142 assertArity("foreach", 3, len(f.args))
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +09001143 abuf := newBuf()
1144 fargs := ev.args(abuf, f.args[1], f.args[2])
1145 varname := string(fargs[0])
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +09001146 ws := newWordScanner(fargs[1])
Fumitoshi Ukaib2670d92015-04-16 10:28:27 +09001147 text := f.args[3]
Fumitoshi Ukai9b10ecf2015-04-15 17:45:50 +09001148 restore := ev.outVars.save(varname)
1149 defer restore()
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +09001150 space := false
Fumitoshi Ukai9da19f62015-05-08 14:39:08 +09001151 for ws.Scan() {
1152 word := ws.Bytes()
Fumitoshi Ukai7bf992d2015-06-25 12:42:19 +09001153 ev.outVars.Assign(varname, &automaticVar{value: word})
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +09001154 if space {
Fumitoshi Ukai145598a2015-06-19 10:08:17 +09001155 writeByte(w, ' ')
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +09001156 }
Fumitoshi Ukaie27a25d2015-04-18 00:31:01 +09001157 text.Eval(w, ev)
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +09001158 space = true
1159 }
Fumitoshi Ukaib06cd9d2015-05-07 12:56:12 +09001160 freeBuf(abuf)
Fumitoshi Ukaid2bcf662015-04-11 01:02:27 +09001161}