fix filter, filter-out
add arity for funcs
diff --git a/func.go b/func.go
index 3e98eb7..8d4e978 100644
--- a/func.go
+++ b/func.go
@@ -12,30 +12,33 @@
// Func is a make function.
// http://www.gnu.org/software/make/manual/make.html#Functions
// TODO(ukai): return error instead of panic?
-// TODO(ukai): each func has nargs, and don't split , more than narg?
type Func func(*Evaluator, []string) string
+func arity(name string, req int, args []string) []string {
+ if len(args) < req {
+ panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `%s'.", len(args), name))
+ }
+ args[req-1] = strings.Join(args[req-1:], ",")
+ // TODO(ukai): ev.evalExpr for all args?
+ Log("%s %q", name, args)
+ return args
+}
+
// http://www.gnu.org/software/make/manual/make.html#Text-Functions
func funcSubst(ev *Evaluator, args []string) string {
- Log("subst %q", args)
- if len(args) < 3 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `subst'.", len(args)))
- }
+ args = arity("subst", 3, args)
from := ev.evalExpr(args[0])
to := ev.evalExpr(args[1])
- text := ev.evalExpr(strings.Join(args[2:], ","))
+ text := ev.evalExpr(args[2])
Log("subst from:%q to:%q text:%q", from, to, text)
return strings.Replace(text, from, to, -1)
}
func funcPatsubst(ev *Evaluator, args []string) string {
- Log("patsubst %q", args)
- if len(args) < 3 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `patsubst'.", len(args)))
- }
+ args = arity("patsubst", 3, args)
pat := ev.evalExpr(args[0])
repl := ev.evalExpr(args[1])
- texts := splitSpaces(ev.evalExpr(strings.Join(args[2:], ",")))
+ texts := splitSpaces(ev.evalExpr(args[2]))
for i, text := range texts {
texts[i] = substPattern(pat, repl, text)
}
@@ -43,30 +46,56 @@
}
func funcStrip(ev *Evaluator, args []string) string {
- text := ev.evalExpr(strings.Join(args, ","))
+ args = arity("strip", 1, args)
+ text := ev.evalExpr(args[0])
return strings.TrimSpace(text)
}
func funcFindstring(ev *Evaluator, args []string) string {
- if len(args) < 2 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `findstring'.", len(args)))
- }
+ args = arity("findstring", 2, args)
f := ev.evalExpr(args[0])
- text := ev.evalExpr(strings.Join(args[1:], ","))
+ text := ev.evalExpr(args[1])
if strings.Index(text, f) >= 0 {
return f
}
return ""
}
-// filter
-// filter-out
+func funcFilter(ev *Evaluator, args []string) string {
+ args = arity("filter", 2, args)
+ patterns := splitSpaces(ev.evalExpr(args[0]))
+ texts := splitSpaces(ev.evalExpr(args[1]))
+ var result []string
+ for _, text := range texts {
+ for _, pat := range patterns {
+ if matchPattern(pat, text) {
+ result = append(result, text)
+ }
+ }
+ }
+ return strings.Join(result, " ")
+}
+
+func funcFilterOut(ev *Evaluator, args []string) string {
+ args = arity("filter-out", 2, args)
+ patterns := splitSpaces(ev.evalExpr(args[0]))
+ texts := splitSpaces(ev.evalExpr(args[1]))
+ var result []string
+Loop:
+ for _, text := range texts {
+ for _, pat := range patterns {
+ if matchPattern(pat, text) {
+ continue Loop
+ }
+ }
+ result = append(result, text)
+ }
+ return strings.Join(result, " ")
+}
func funcSort(ev *Evaluator, args []string) string {
- if len(args) <= 0 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `sort'.", len(args)))
- }
- toks := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ args = arity("sort", 1, args)
+ toks := splitSpaces(ev.evalExpr(args[0]))
sort.Strings(toks)
// Remove duplicate words.
@@ -91,14 +120,12 @@
}
func funcWord(ev *Evaluator, args []string) string {
- if len(args) < 2 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `word'.", len(args)))
- }
+ args = arity("word", 2, args)
index := numericValueForFunc(ev, args[0], "word", "first")
if index == 0 {
Error(ev.filename, ev.lineno, `*** first argument to "word" function must be greater than 0.`)
}
- toks := splitSpaces(ev.evalExpr(strings.Join(args[1:], ",")))
+ toks := splitSpaces(ev.evalExpr(args[1]))
if index-1 >= len(toks) {
return ""
}
@@ -106,9 +133,7 @@
}
func funcWordlist(ev *Evaluator, args []string) string {
- if len(args) < 3 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `wordlist'.", len(args)))
- }
+ args = arity("wordlist", 3, args)
si := numericValueForFunc(ev, args[0], "wordlist", "first")
if si == 0 {
Error(ev.filename, ev.lineno, `*** invalid first argument to "wordlist" function: ""`, args[0])
@@ -118,7 +143,7 @@
Error(ev.filename, ev.lineno, `*** invalid second argument to "wordlist" function: ""`, args[1])
}
- toks := splitSpaces(ev.evalExpr(strings.Join(args[2:], ",")))
+ toks := splitSpaces(ev.evalExpr(args[2]))
if si-1 >= len(toks) {
return ""
}
@@ -130,12 +155,14 @@
}
func funcWords(ev *Evaluator, args []string) string {
- toks := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ args = arity("words", 1, args)
+ toks := splitSpaces(ev.evalExpr(args[0]))
return strconv.Itoa(len(toks))
}
func funcFirstword(ev *Evaluator, args []string) string {
- toks := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ args = arity("firstword", 1, args)
+ toks := splitSpaces(ev.evalExpr(args[0]))
if len(toks) == 0 {
return ""
}
@@ -143,7 +170,8 @@
}
func funcLastword(ev *Evaluator, args []string) string {
- toks := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ args = arity("lastword", 1, args)
+ toks := splitSpaces(ev.evalExpr(args[0]))
if len(toks) == 0 {
return ""
}
@@ -152,8 +180,8 @@
// http://www.gnu.org/software/make/manual/make.html#File-Name-Functions
func funcWildcard(ev *Evaluator, args []string) string {
- Log("wildcard %q", args)
- pattern := ev.evalExpr(strings.Join(args, ","))
+ args = arity("wildcard", 1, args)
+ pattern := ev.evalExpr(args[0])
files, err := filepath.Glob(pattern)
if err != nil {
panic(err)
@@ -163,8 +191,8 @@
// https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html#File-Name-Functions
func funcDir(ev *Evaluator, args []string) string {
- Log("dir %q", args)
- names := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ args = arity("dir", 1, args)
+ names := splitSpaces(ev.evalExpr(args[0]))
if len(names) == 0 {
return ""
}
@@ -176,8 +204,8 @@
}
func funcNotdir(ev *Evaluator, args []string) string {
- Log("notdir %q", args)
- names := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ args = arity("notdir", 1, args)
+ names := splitSpaces(ev.evalExpr(args[0]))
if len(names) == 0 {
return ""
}
@@ -193,7 +221,8 @@
}
func funcSuffix(ev *Evaluator, args []string) string {
- toks := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ args = arity("suffix", 1, args)
+ toks := splitSpaces(ev.evalExpr(args[0]))
var result []string
for _, tok := range toks {
e := filepath.Ext(tok)
@@ -205,7 +234,8 @@
}
func funcBasename(ev *Evaluator, args []string) string {
- toks := splitSpaces(ev.evalExpr(strings.Join(args, ",")))
+ args = arity("basename", 1, args)
+ toks := splitSpaces(ev.evalExpr(args[0]))
var result []string
for _, tok := range toks {
b := stripExt(tok)
@@ -215,11 +245,9 @@
}
func funcAddsuffix(ev *Evaluator, args []string) string {
- if len(args) < 2 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `addsuffix'.", len(args)))
- }
+ args = arity("addsuffix", 2, args)
suf := ev.evalExpr(args[0])
- toks := splitSpaces(ev.evalExpr(strings.Join(args[1:], ",")))
+ toks := splitSpaces(ev.evalExpr(args[1]))
for i, tok := range toks {
toks[i] = fmt.Sprintf("%s%s", tok, suf)
}
@@ -227,11 +255,9 @@
}
func funcAddprefix(ev *Evaluator, args []string) string {
- if len(args) < 2 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `addprefix'.", len(args)))
- }
+ args = arity("addprefix", 2, args)
pre := ev.evalExpr(args[0])
- toks := splitSpaces(ev.evalExpr(strings.Join(args[1:], ",")))
+ toks := splitSpaces(ev.evalExpr(args[1]))
for i, tok := range toks {
toks[i] = fmt.Sprintf("%s%s", pre, tok)
}
@@ -239,11 +265,10 @@
}
func funcRealpath(ev *Evaluator, args []string) string {
- Log("realpath %q", args)
- names := strings.Split(ev.evalExpr(strings.Join(args, ",")), " \t")
+ args = arity("realpath", 1, args)
+ names := splitSpaces(ev.evalExpr(args[0]))
var realpaths []string
for _, name := range names {
- name = strings.TrimSpace(name)
name, err := filepath.Abs(name)
if err != nil {
Log("abs: %v", err)
@@ -260,11 +285,10 @@
}
func funcAbspath(ev *Evaluator, args []string) string {
- Log("abspath %q", args)
- names := strings.Split(ev.evalExpr(strings.Join(args, ",")), " \t")
+ args = arity("abspath", 1, args)
+ names := splitSpaces(ev.evalExpr(args[0]))
var realpaths []string
for _, name := range names {
- name = strings.TrimSpace(name)
name, err := filepath.Abs(name)
if err != nil {
Log("abs: %v", err)
@@ -277,15 +301,12 @@
// http://www.gnu.org/software/make/manual/make.html#Conditional-Functions
func funcIf(ev *Evaluator, args []string) string {
- if len(args) < 3 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `if'.", len(args)))
- }
+ args = arity("if", 3, args)
cond := ev.evalExpr(args[0])
- if len(cond) > 0 {
+ if cond != "" {
return ev.evalExpr(args[1])
- } else {
- return ev.evalExpr(strings.Join(args[2:], ","))
}
+ return ev.evalExpr(args[2])
}
func funcOr(ev *Evaluator, args []string) string {
@@ -293,7 +314,7 @@
panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `or'.", len(args)))
}
cond := ev.evalExpr(args[0])
- if len(cond) == 0 {
+ if cond == "" {
// For some reason, "and" and "or" do not use args[2:]
return ev.evalExpr(strings.TrimSpace(args[1]))
}
@@ -305,7 +326,7 @@
panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `and'.", len(args)))
}
cond := ev.evalExpr(args[0])
- if len(cond) > 0 {
+ if cond != "" {
// For some reason, "and" and "or" do not use args[2:]
return ev.evalExpr(strings.TrimSpace(args[1]))
}
@@ -314,13 +335,11 @@
// http://www.gnu.org/software/make/manual/make.html#Foreach-Function
func funcForeach(ev *Evaluator, args []string) string {
- if len(args) < 3 {
- panic(fmt.Sprintf("*** insufficient number of arguments (%d) to function `foreach'.", len(args)))
- }
+ args = arity("foreach", 3, args)
var result []string
varName := ev.evalExpr(args[0])
values := splitSpaces(ev.evalExpr(args[1]))
- expr := strings.Join(args[2:], ",")
+ expr := args[2]
for _, val := range values {
newVars := NewVarTab(ev.vars)
newVars.Assign(varName,
@@ -338,7 +357,8 @@
// http://www.gnu.org/software/make/manual/make.html#Eval-Function
func funcEval(ev *Evaluator, args []string) string {
- s := ev.evalExpr(strings.Join(args, ","))
+ args = arity("eval", 1, args)
+ s := ev.evalExpr(args[0])
mk, err := ParseMakefileString(s, "*eval*")
if err != nil {
panic(err)
@@ -361,8 +381,8 @@
// http://www.gnu.org/software/make/manual/make.html#Shell-Function
func funcShell(ev *Evaluator, args []string) string {
- Log("shell %q", args)
- arg := ev.evalExpr(strings.Join(args, ","))
+ args = arity("shell", 1, args)
+ arg := ev.evalExpr(args[0])
cmdline := []string{"/bin/sh", "-c", arg}
cmd := exec.Cmd{
Path: cmdline[0],
@@ -380,7 +400,6 @@
// https://www.gnu.org/software/make/manual/html_node/Call-Function.html#Call-Function
func funcCall(ev *Evaluator, args []string) string {
- Log("call %q", args)
f := ev.LookupVar(args[0]).String()
Log("call func %q => %q", args[0], f)
localVars := NewVarTab(ev.VarTab())
@@ -401,29 +420,29 @@
// https://www.gnu.org/software/make/manual/html_node/Flavor-Function.html#Flavor-Function
func funcFlavor(ev *Evaluator, args []string) string {
- Log("flavor %q", args)
- vname := strings.Join(args, ",")
+ args = arity("flavor", 1, args)
+ vname := args[0]
return ev.LookupVar(vname).Flavor()
}
// http://www.gnu.org/software/make/manual/make.html#Make-Control-Functions
func funcInfo(ev *Evaluator, args []string) string {
- Log("warning %q", args)
- arg := ev.evalExpr(strings.Join(args, ","))
+ args = arity("warning", 1, args)
+ arg := ev.evalExpr(args[0])
fmt.Printf("%s\n", arg)
return ""
}
func funcWarning(ev *Evaluator, args []string) string {
- Log("warning %q", args)
- arg := ev.evalExpr(strings.Join(args, ","))
+ args = arity("warning", 1, args)
+ arg := ev.evalExpr(args[0])
fmt.Printf("%s:%d: %s\n", ev.filename, ev.lineno, arg)
return ""
}
func funcError(ev *Evaluator, args []string) string {
- Log("warning %q", args)
- arg := ev.evalExpr(strings.Join(args, ","))
+ args = arity("error", 1, args)
+ arg := ev.evalExpr(args[0])
Error(ev.filename, ev.lineno, "*** %s.", arg)
return ""
}