Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "os/exec" |
| 6 | "path/filepath" |
Shinichiro Hamaji | 13b30d9 | 2015-04-03 14:42:21 +0900 | [diff] [blame] | 7 | "sort" |
Shinichiro Hamaji | e708a9d | 2015-04-03 14:34:35 +0900 | [diff] [blame] | 8 | "strconv" |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 9 | "strings" |
| 10 | ) |
| 11 | |
| 12 | // Func is a make function. |
| 13 | // http://www.gnu.org/software/make/manual/make.html#Functions |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 14 | // TODO(ukai): return error instead of panic? |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 15 | type Func func(*Evaluator, []string) string |
| 16 | |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 17 | func arity(name string, req int, args []string) []string { |
| 18 | if len(args) < req { |
| 19 | panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `%s'.", len(args), name)) |
| 20 | } |
| 21 | args[req-1] = strings.Join(args[req-1:], ",") |
| 22 | // TODO(ukai): ev.evalExpr for all args? |
| 23 | Log("%s %q", name, args) |
| 24 | return args |
| 25 | } |
| 26 | |
Shinichiro Hamaji | 4125cf4 | 2015-04-03 11:42:28 +0900 | [diff] [blame] | 27 | // http://www.gnu.org/software/make/manual/make.html#Text-Functions |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 28 | func funcSubst(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 29 | args = arity("subst", 3, args) |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 30 | from := ev.evalExpr(args[0]) |
| 31 | to := ev.evalExpr(args[1]) |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 32 | text := ev.evalExpr(args[2]) |
Fumitoshi Ukai | bb79a9d | 2015-04-02 12:46:54 +0900 | [diff] [blame] | 33 | Log("subst from:%q to:%q text:%q", from, to, text) |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 34 | return strings.Replace(text, from, to, -1) |
| 35 | } |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 36 | |
Shinichiro Hamaji | ea8b56d | 2015-04-01 03:39:29 +0900 | [diff] [blame] | 37 | func funcPatsubst(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 38 | args = arity("patsubst", 3, args) |
Shinichiro Hamaji | ea8b56d | 2015-04-01 03:39:29 +0900 | [diff] [blame] | 39 | pat := ev.evalExpr(args[0]) |
| 40 | repl := ev.evalExpr(args[1]) |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 41 | texts := splitSpaces(ev.evalExpr(args[2])) |
Shinichiro Hamaji | ea8b56d | 2015-04-01 03:39:29 +0900 | [diff] [blame] | 42 | for i, text := range texts { |
| 43 | texts[i] = substPattern(pat, repl, text) |
| 44 | } |
| 45 | return strings.Join(texts, " ") |
| 46 | } |
| 47 | |
Shinichiro Hamaji | 4125cf4 | 2015-04-03 11:42:28 +0900 | [diff] [blame] | 48 | func funcStrip(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 49 | args = arity("strip", 1, args) |
| 50 | text := ev.evalExpr(args[0]) |
Shinichiro Hamaji | 4125cf4 | 2015-04-03 11:42:28 +0900 | [diff] [blame] | 51 | return strings.TrimSpace(text) |
| 52 | } |
| 53 | |
| 54 | func funcFindstring(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 55 | args = arity("findstring", 2, args) |
Shinichiro Hamaji | 47ffb72 | 2015-04-03 11:48:45 +0900 | [diff] [blame] | 56 | f := ev.evalExpr(args[0]) |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 57 | text := ev.evalExpr(args[1]) |
Shinichiro Hamaji | 47ffb72 | 2015-04-03 11:48:45 +0900 | [diff] [blame] | 58 | if strings.Index(text, f) >= 0 { |
| 59 | return f |
| 60 | } |
Shinichiro Hamaji | 4125cf4 | 2015-04-03 11:42:28 +0900 | [diff] [blame] | 61 | return "" |
| 62 | } |
| 63 | |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 64 | func funcFilter(ev *Evaluator, args []string) string { |
| 65 | args = arity("filter", 2, args) |
| 66 | patterns := splitSpaces(ev.evalExpr(args[0])) |
| 67 | texts := splitSpaces(ev.evalExpr(args[1])) |
| 68 | var result []string |
| 69 | for _, text := range texts { |
| 70 | for _, pat := range patterns { |
| 71 | if matchPattern(pat, text) { |
| 72 | result = append(result, text) |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | return strings.Join(result, " ") |
| 77 | } |
| 78 | |
| 79 | func funcFilterOut(ev *Evaluator, args []string) string { |
| 80 | args = arity("filter-out", 2, args) |
| 81 | patterns := splitSpaces(ev.evalExpr(args[0])) |
| 82 | texts := splitSpaces(ev.evalExpr(args[1])) |
| 83 | var result []string |
| 84 | Loop: |
| 85 | for _, text := range texts { |
| 86 | for _, pat := range patterns { |
| 87 | if matchPattern(pat, text) { |
| 88 | continue Loop |
| 89 | } |
| 90 | } |
| 91 | result = append(result, text) |
| 92 | } |
| 93 | return strings.Join(result, " ") |
| 94 | } |
Shinichiro Hamaji | 13b30d9 | 2015-04-03 14:42:21 +0900 | [diff] [blame] | 95 | |
| 96 | func funcSort(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 97 | args = arity("sort", 1, args) |
| 98 | toks := splitSpaces(ev.evalExpr(args[0])) |
Shinichiro Hamaji | 13b30d9 | 2015-04-03 14:42:21 +0900 | [diff] [blame] | 99 | sort.Strings(toks) |
| 100 | |
| 101 | // Remove duplicate words. |
| 102 | var prev string |
| 103 | var result []string |
| 104 | for _, tok := range toks { |
| 105 | if prev != tok { |
| 106 | result = append(result, tok) |
| 107 | prev = tok |
| 108 | } |
| 109 | } |
| 110 | return strings.Join(result, " ") |
| 111 | } |
Shinichiro Hamaji | e708a9d | 2015-04-03 14:34:35 +0900 | [diff] [blame] | 112 | |
| 113 | func numericValueForFunc(ev *Evaluator, a string, funcName string, nth string) int { |
| 114 | a = strings.TrimSpace(ev.evalExpr(a)) |
| 115 | n, err := strconv.Atoi(a) |
| 116 | if err != nil || n < 0 { |
| 117 | Error(ev.filename, ev.lineno, `*** non-numeric %s argument to "%s" function: "%s".`, nth, funcName, a) |
| 118 | } |
| 119 | return n |
| 120 | } |
| 121 | |
| 122 | func funcWord(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 123 | args = arity("word", 2, args) |
Shinichiro Hamaji | e708a9d | 2015-04-03 14:34:35 +0900 | [diff] [blame] | 124 | index := numericValueForFunc(ev, args[0], "word", "first") |
| 125 | if index == 0 { |
| 126 | Error(ev.filename, ev.lineno, `*** first argument to "word" function must be greater than 0.`) |
| 127 | } |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 128 | toks := splitSpaces(ev.evalExpr(args[1])) |
Shinichiro Hamaji | e708a9d | 2015-04-03 14:34:35 +0900 | [diff] [blame] | 129 | if index-1 >= len(toks) { |
| 130 | return "" |
| 131 | } |
| 132 | return ev.evalExpr(toks[index-1]) |
| 133 | } |
| 134 | |
| 135 | func funcWordlist(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 136 | args = arity("wordlist", 3, args) |
Shinichiro Hamaji | e708a9d | 2015-04-03 14:34:35 +0900 | [diff] [blame] | 137 | si := numericValueForFunc(ev, args[0], "wordlist", "first") |
| 138 | if si == 0 { |
| 139 | Error(ev.filename, ev.lineno, `*** invalid first argument to "wordlist" function: ""`, args[0]) |
| 140 | } |
| 141 | ei := numericValueForFunc(ev, args[1], "wordlist", "second") |
| 142 | if ei == 0 { |
| 143 | Error(ev.filename, ev.lineno, `*** invalid second argument to "wordlist" function: ""`, args[1]) |
| 144 | } |
| 145 | |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 146 | toks := splitSpaces(ev.evalExpr(args[2])) |
Shinichiro Hamaji | e708a9d | 2015-04-03 14:34:35 +0900 | [diff] [blame] | 147 | if si-1 >= len(toks) { |
| 148 | return "" |
| 149 | } |
| 150 | if ei-1 >= len(toks) { |
| 151 | ei = len(toks) |
| 152 | } |
| 153 | |
| 154 | return strings.Join(toks[si-1:ei], " ") |
| 155 | } |
| 156 | |
| 157 | func funcWords(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 158 | args = arity("words", 1, args) |
| 159 | toks := splitSpaces(ev.evalExpr(args[0])) |
Shinichiro Hamaji | e708a9d | 2015-04-03 14:34:35 +0900 | [diff] [blame] | 160 | return strconv.Itoa(len(toks)) |
| 161 | } |
| 162 | |
| 163 | func funcFirstword(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 164 | args = arity("firstword", 1, args) |
| 165 | toks := splitSpaces(ev.evalExpr(args[0])) |
Shinichiro Hamaji | e708a9d | 2015-04-03 14:34:35 +0900 | [diff] [blame] | 166 | if len(toks) == 0 { |
| 167 | return "" |
| 168 | } |
| 169 | return toks[0] |
| 170 | } |
| 171 | |
| 172 | func funcLastword(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 173 | args = arity("lastword", 1, args) |
| 174 | toks := splitSpaces(ev.evalExpr(args[0])) |
Shinichiro Hamaji | e708a9d | 2015-04-03 14:34:35 +0900 | [diff] [blame] | 175 | if len(toks) == 0 { |
| 176 | return "" |
| 177 | } |
| 178 | return toks[len(toks)-1] |
| 179 | } |
Shinichiro Hamaji | 4125cf4 | 2015-04-03 11:42:28 +0900 | [diff] [blame] | 180 | |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 181 | // http://www.gnu.org/software/make/manual/make.html#File-Name-Functions |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 182 | func funcWildcard(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 183 | args = arity("wildcard", 1, args) |
| 184 | pattern := ev.evalExpr(args[0]) |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 185 | files, err := filepath.Glob(pattern) |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 186 | if err != nil { |
| 187 | panic(err) |
| 188 | } |
| 189 | return strings.Join(files, " ") |
| 190 | } |
| 191 | |
Fumitoshi Ukai | bb79a9d | 2015-04-02 12:46:54 +0900 | [diff] [blame] | 192 | // https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html#File-Name-Functions |
| 193 | func funcDir(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 194 | args = arity("dir", 1, args) |
| 195 | names := splitSpaces(ev.evalExpr(args[0])) |
Fumitoshi Ukai | 0a83803 | 2015-04-03 17:58:44 +0900 | [diff] [blame] | 196 | if len(names) == 0 { |
Fumitoshi Ukai | bb79a9d | 2015-04-02 12:46:54 +0900 | [diff] [blame] | 197 | return "" |
| 198 | } |
Fumitoshi Ukai | 0a83803 | 2015-04-03 17:58:44 +0900 | [diff] [blame] | 199 | var dirs []string |
| 200 | for _, name := range names { |
| 201 | dirs = append(dirs, filepath.Dir(name)+string(filepath.Separator)) |
| 202 | } |
| 203 | return strings.Join(dirs, " ") |
Fumitoshi Ukai | bb79a9d | 2015-04-02 12:46:54 +0900 | [diff] [blame] | 204 | } |
| 205 | |
Fumitoshi Ukai | 538a315 | 2015-04-02 23:39:12 +0900 | [diff] [blame] | 206 | func funcNotdir(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 207 | args = arity("notdir", 1, args) |
| 208 | names := splitSpaces(ev.evalExpr(args[0])) |
Fumitoshi Ukai | 0a83803 | 2015-04-03 17:58:44 +0900 | [diff] [blame] | 209 | if len(names) == 0 { |
Fumitoshi Ukai | 538a315 | 2015-04-02 23:39:12 +0900 | [diff] [blame] | 210 | return "" |
| 211 | } |
Fumitoshi Ukai | 0a83803 | 2015-04-03 17:58:44 +0900 | [diff] [blame] | 212 | var notdirs []string |
| 213 | for _, name := range names { |
| 214 | if name == string(filepath.Separator) { |
| 215 | notdirs = append(notdirs, "") |
| 216 | continue |
| 217 | } |
| 218 | notdirs = append(notdirs, filepath.Base(name)) |
| 219 | } |
| 220 | return strings.Join(notdirs, " ") |
Fumitoshi Ukai | 538a315 | 2015-04-02 23:39:12 +0900 | [diff] [blame] | 221 | } |
| 222 | |
Shinichiro Hamaji | 5e2c3c7 | 2015-04-03 15:04:54 +0900 | [diff] [blame] | 223 | func funcSuffix(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 224 | args = arity("suffix", 1, args) |
| 225 | toks := splitSpaces(ev.evalExpr(args[0])) |
Shinichiro Hamaji | 5e2c3c7 | 2015-04-03 15:04:54 +0900 | [diff] [blame] | 226 | var result []string |
| 227 | for _, tok := range toks { |
| 228 | e := filepath.Ext(tok) |
| 229 | if len(e) > 0 { |
| 230 | result = append(result, e) |
| 231 | } |
| 232 | } |
| 233 | return strings.Join(result, " ") |
| 234 | } |
| 235 | |
| 236 | func funcBasename(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 237 | args = arity("basename", 1, args) |
| 238 | toks := splitSpaces(ev.evalExpr(args[0])) |
Shinichiro Hamaji | 5e2c3c7 | 2015-04-03 15:04:54 +0900 | [diff] [blame] | 239 | var result []string |
| 240 | for _, tok := range toks { |
| 241 | b := stripExt(tok) |
| 242 | result = append(result, b) |
| 243 | } |
| 244 | return strings.Join(result, " ") |
| 245 | } |
| 246 | |
| 247 | func funcAddsuffix(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 248 | args = arity("addsuffix", 2, args) |
Shinichiro Hamaji | 5e2c3c7 | 2015-04-03 15:04:54 +0900 | [diff] [blame] | 249 | suf := ev.evalExpr(args[0]) |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 250 | toks := splitSpaces(ev.evalExpr(args[1])) |
Shinichiro Hamaji | 5e2c3c7 | 2015-04-03 15:04:54 +0900 | [diff] [blame] | 251 | for i, tok := range toks { |
| 252 | toks[i] = fmt.Sprintf("%s%s", tok, suf) |
| 253 | } |
| 254 | return strings.Join(toks, " ") |
| 255 | } |
| 256 | |
| 257 | func funcAddprefix(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 258 | args = arity("addprefix", 2, args) |
Shinichiro Hamaji | 5e2c3c7 | 2015-04-03 15:04:54 +0900 | [diff] [blame] | 259 | pre := ev.evalExpr(args[0]) |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 260 | toks := splitSpaces(ev.evalExpr(args[1])) |
Shinichiro Hamaji | 5e2c3c7 | 2015-04-03 15:04:54 +0900 | [diff] [blame] | 261 | for i, tok := range toks { |
| 262 | toks[i] = fmt.Sprintf("%s%s", pre, tok) |
| 263 | } |
| 264 | return strings.Join(toks, " ") |
| 265 | } |
| 266 | |
Fumitoshi Ukai | c520636 | 2015-04-01 21:37:53 +0900 | [diff] [blame] | 267 | func funcRealpath(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 268 | args = arity("realpath", 1, args) |
| 269 | names := splitSpaces(ev.evalExpr(args[0])) |
Fumitoshi Ukai | c520636 | 2015-04-01 21:37:53 +0900 | [diff] [blame] | 270 | var realpaths []string |
| 271 | for _, name := range names { |
Fumitoshi Ukai | c520636 | 2015-04-01 21:37:53 +0900 | [diff] [blame] | 272 | name, err := filepath.Abs(name) |
| 273 | if err != nil { |
| 274 | Log("abs: %v", err) |
| 275 | continue |
| 276 | } |
| 277 | name, err = filepath.EvalSymlinks(name) |
| 278 | if err != nil { |
| 279 | Log("realpath: %v", err) |
| 280 | continue |
| 281 | } |
| 282 | realpaths = append(realpaths, name) |
| 283 | } |
| 284 | return strings.Join(realpaths, " ") |
| 285 | } |
| 286 | |
| 287 | func funcAbspath(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 288 | args = arity("abspath", 1, args) |
| 289 | names := splitSpaces(ev.evalExpr(args[0])) |
Fumitoshi Ukai | c520636 | 2015-04-01 21:37:53 +0900 | [diff] [blame] | 290 | var realpaths []string |
| 291 | for _, name := range names { |
Fumitoshi Ukai | c520636 | 2015-04-01 21:37:53 +0900 | [diff] [blame] | 292 | name, err := filepath.Abs(name) |
| 293 | if err != nil { |
| 294 | Log("abs: %v", err) |
| 295 | continue |
| 296 | } |
| 297 | realpaths = append(realpaths, name) |
| 298 | } |
| 299 | return strings.Join(realpaths, " ") |
| 300 | } |
| 301 | |
Shinichiro Hamaji | 48a85e3 | 2015-04-03 17:03:49 +0900 | [diff] [blame] | 302 | // http://www.gnu.org/software/make/manual/make.html#Conditional-Functions |
| 303 | func funcIf(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 304 | args = arity("if", 3, args) |
Fumitoshi Ukai | b8bdfd5 | 2015-04-03 23:08:57 +0900 | [diff] [blame] | 305 | cond := ev.evalExpr(strings.TrimSpace(args[0])) |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 306 | if cond != "" { |
Shinichiro Hamaji | 48a85e3 | 2015-04-03 17:03:49 +0900 | [diff] [blame] | 307 | return ev.evalExpr(args[1]) |
Shinichiro Hamaji | 48a85e3 | 2015-04-03 17:03:49 +0900 | [diff] [blame] | 308 | } |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 309 | return ev.evalExpr(args[2]) |
Shinichiro Hamaji | 48a85e3 | 2015-04-03 17:03:49 +0900 | [diff] [blame] | 310 | } |
| 311 | |
| 312 | func funcOr(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | b8bdfd5 | 2015-04-03 23:08:57 +0900 | [diff] [blame] | 313 | for _, arg := range args { |
| 314 | cond := ev.evalExpr(strings.TrimSpace(arg)) |
| 315 | if cond != "" { |
| 316 | return cond |
| 317 | } |
Shinichiro Hamaji | 48a85e3 | 2015-04-03 17:03:49 +0900 | [diff] [blame] | 318 | } |
Fumitoshi Ukai | b8bdfd5 | 2015-04-03 23:08:57 +0900 | [diff] [blame] | 319 | return "" |
Shinichiro Hamaji | 48a85e3 | 2015-04-03 17:03:49 +0900 | [diff] [blame] | 320 | } |
| 321 | |
| 322 | func funcAnd(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | b8bdfd5 | 2015-04-03 23:08:57 +0900 | [diff] [blame] | 323 | var cond string |
| 324 | for _, arg := range args { |
| 325 | cond = ev.evalExpr(strings.TrimSpace(arg)) |
| 326 | if cond == "" { |
| 327 | return "" |
| 328 | } |
Shinichiro Hamaji | 48a85e3 | 2015-04-03 17:03:49 +0900 | [diff] [blame] | 329 | } |
Fumitoshi Ukai | b8bdfd5 | 2015-04-03 23:08:57 +0900 | [diff] [blame] | 330 | return cond |
Shinichiro Hamaji | 48a85e3 | 2015-04-03 17:03:49 +0900 | [diff] [blame] | 331 | } |
| 332 | |
Shinichiro Hamaji | 8c75f0b | 2015-04-03 16:35:21 +0900 | [diff] [blame] | 333 | // http://www.gnu.org/software/make/manual/make.html#Foreach-Function |
| 334 | func funcForeach(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 335 | args = arity("foreach", 3, args) |
Shinichiro Hamaji | 8c75f0b | 2015-04-03 16:35:21 +0900 | [diff] [blame] | 336 | var result []string |
| 337 | varName := ev.evalExpr(args[0]) |
| 338 | values := splitSpaces(ev.evalExpr(args[1])) |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 339 | expr := args[2] |
Shinichiro Hamaji | 8c75f0b | 2015-04-03 16:35:21 +0900 | [diff] [blame] | 340 | for _, val := range values { |
| 341 | newVars := NewVarTab(ev.vars) |
| 342 | newVars.Assign(varName, |
| 343 | SimpleVar{ |
| 344 | value: val, |
| 345 | origin: "automatic", |
| 346 | }) |
| 347 | oldVars := ev.vars |
| 348 | ev.vars = newVars |
| 349 | result = append(result, ev.evalExpr(expr)) |
| 350 | ev.vars = oldVars |
| 351 | } |
| 352 | return strings.Join(result, " ") |
| 353 | } |
| 354 | |
Shinichiro Hamaji | 8c5b25a | 2015-04-04 18:46:37 +0900 | [diff] [blame] | 355 | // http://www.gnu.org/software/make/manual/make.html#Value-Function |
| 356 | func funcValue(ev *Evaluator, args []string) string { |
| 357 | v := ev.LookupVar(strings.Join(args, ",")) |
| 358 | return v.String() |
| 359 | } |
| 360 | |
Shinichiro Hamaji | 8c75f0b | 2015-04-03 16:35:21 +0900 | [diff] [blame] | 361 | // http://www.gnu.org/software/make/manual/make.html#Eval-Function |
| 362 | func funcEval(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 363 | args = arity("eval", 1, args) |
| 364 | s := ev.evalExpr(args[0]) |
Shinichiro Hamaji | b4ac1b5 | 2015-04-03 16:44:04 +0900 | [diff] [blame] | 365 | mk, err := ParseMakefileString(s, "*eval*") |
| 366 | if err != nil { |
| 367 | panic(err) |
| 368 | } |
| 369 | |
| 370 | er, err2 := Eval(mk, ev.VarTab()) |
| 371 | if err2 != nil { |
| 372 | panic(err2) |
| 373 | } |
| 374 | |
| 375 | for k, v := range er.vars.Vars() { |
| 376 | ev.outVars.Assign(k, v) |
| 377 | } |
| 378 | for _, r := range er.rules { |
| 379 | ev.outRules = append(ev.outRules, r) |
| 380 | } |
| 381 | |
Shinichiro Hamaji | 8c75f0b | 2015-04-03 16:35:21 +0900 | [diff] [blame] | 382 | return "" |
| 383 | } |
| 384 | |
Shinichiro Hamaji | 7ff34db | 2015-04-04 18:55:20 +0900 | [diff] [blame^] | 385 | // http://www.gnu.org/software/make/manual/make.html#Origin-Function |
| 386 | func funcOrigin(ev *Evaluator, args []string) string { |
| 387 | v := ev.LookupVar(strings.Join(args, ",")) |
| 388 | return v.Origin() |
| 389 | } |
| 390 | |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 391 | // http://www.gnu.org/software/make/manual/make.html#Shell-Function |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 392 | func funcShell(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 393 | args = arity("shell", 1, args) |
| 394 | arg := ev.evalExpr(args[0]) |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 395 | cmdline := []string{"/bin/sh", "-c", arg} |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 396 | cmd := exec.Cmd{ |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 397 | Path: cmdline[0], |
| 398 | Args: cmdline, |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 399 | } |
| 400 | out, err := cmd.CombinedOutput() |
| 401 | if err != nil { |
Shinichiro Hamaji | 79abd18 | 2015-04-03 11:07:38 +0900 | [diff] [blame] | 402 | Log("$(shell %q) failed: %q", args, err) |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 403 | } |
Shinichiro Hamaji | 79abd18 | 2015-04-03 11:07:38 +0900 | [diff] [blame] | 404 | |
| 405 | r := string(out) |
| 406 | r = strings.TrimRight(r, "\n") |
| 407 | return strings.Replace(r, "\n", " ", -1) |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 408 | } |
| 409 | |
Fumitoshi Ukai | bb79a9d | 2015-04-02 12:46:54 +0900 | [diff] [blame] | 410 | // https://www.gnu.org/software/make/manual/html_node/Call-Function.html#Call-Function |
| 411 | func funcCall(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | bb79a9d | 2015-04-02 12:46:54 +0900 | [diff] [blame] | 412 | f := ev.LookupVar(args[0]).String() |
| 413 | Log("call func %q => %q", args[0], f) |
| 414 | localVars := NewVarTab(ev.VarTab()) |
| 415 | for i, argstr := range args[1:] { |
| 416 | arg := ev.evalExpr(argstr) |
| 417 | Log("call $%d: %q=>%q", i+1, argstr, arg) |
| 418 | localVars.Assign(fmt.Sprintf("%d", i+1), |
| 419 | RecursiveVar{ |
| 420 | expr: arg, |
| 421 | origin: "automatic", // ?? |
| 422 | }) |
| 423 | } |
| 424 | ev = newEvaluator(localVars) |
| 425 | r := ev.evalExpr(f) |
| 426 | Log("call %q return %q", args[0], r) |
| 427 | return r |
| 428 | } |
| 429 | |
Fumitoshi Ukai | 8edcb79 | 2015-04-02 11:23:23 +0900 | [diff] [blame] | 430 | // https://www.gnu.org/software/make/manual/html_node/Flavor-Function.html#Flavor-Function |
| 431 | func funcFlavor(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 432 | args = arity("flavor", 1, args) |
| 433 | vname := args[0] |
Fumitoshi Ukai | 8edcb79 | 2015-04-02 11:23:23 +0900 | [diff] [blame] | 434 | return ev.LookupVar(vname).Flavor() |
| 435 | } |
| 436 | |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 437 | // http://www.gnu.org/software/make/manual/make.html#Make-Control-Functions |
Shinichiro Hamaji | c565e44 | 2015-04-03 11:26:27 +0900 | [diff] [blame] | 438 | func funcInfo(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 439 | args = arity("warning", 1, args) |
| 440 | arg := ev.evalExpr(args[0]) |
Shinichiro Hamaji | c565e44 | 2015-04-03 11:26:27 +0900 | [diff] [blame] | 441 | fmt.Printf("%s\n", arg) |
| 442 | return "" |
| 443 | } |
| 444 | |
Fumitoshi Ukai | e520f26 | 2015-03-31 17:27:03 +0900 | [diff] [blame] | 445 | func funcWarning(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 446 | args = arity("warning", 1, args) |
| 447 | arg := ev.evalExpr(args[0]) |
Fumitoshi Ukai | f2f8456 | 2015-03-30 19:47:45 +0900 | [diff] [blame] | 448 | fmt.Printf("%s:%d: %s\n", ev.filename, ev.lineno, arg) |
| 449 | return "" |
| 450 | } |
Shinichiro Hamaji | c565e44 | 2015-04-03 11:26:27 +0900 | [diff] [blame] | 451 | |
| 452 | func funcError(ev *Evaluator, args []string) string { |
Fumitoshi Ukai | 0b5e18b | 2015-04-03 22:57:17 +0900 | [diff] [blame] | 453 | args = arity("error", 1, args) |
| 454 | arg := ev.evalExpr(args[0]) |
Shinichiro Hamaji | c565e44 | 2015-04-03 11:26:27 +0900 | [diff] [blame] | 455 | Error(ev.filename, ev.lineno, "*** %s.", arg) |
| 456 | return "" |
| 457 | } |