introduce func compactor.

$(eval ## comment) will be nop when parsed.
diff --git a/func.go b/func.go
index 7d7af5a..fc9350c 100644
--- a/func.go
+++ b/func.go
@@ -612,9 +612,6 @@
 func (f *funcEval) Eval(w io.Writer, ev *Evaluator) {
 	assertArity("eval", 1, len(f.args))
 	s := ev.Value(f.args[1])
-	if len(s) == 0 || (s[0] == '#' && bytes.IndexByte(s, '\n') < 0) {
-		return
-	}
 	mk, err := ParseMakefileBytes(s, ev.filename, ev.lineno)
 	if err != nil {
 		panic(err)
@@ -625,6 +622,47 @@
 	}
 }
 
+func (f *funcEval) Compact() Func {
+	if len(f.args)-1 < 1 {
+		return f
+	}
+	switch f.args[1].(type) {
+	case literal, tmpval:
+	default:
+		// TODO(ukai): eval -> varassign. e.g. $(eval foo := $(x))
+		return f
+	}
+	arg := f.args[1].String()
+	arg = stripComment(arg)
+	if arg == "" {
+		return &funcNop{expr: f.String()}
+	}
+	// TODO(ukai): preserve comment for String()?
+	f.args[1] = literal(arg)
+	return f
+}
+
+func stripComment(arg string) string {
+	for {
+		i := strings.Index(arg, "#")
+		if i < 0 {
+			return arg
+		}
+		eol := strings.Index(arg[i:], "\n")
+		if eol < 0 {
+			return arg[:i]
+		}
+		arg = arg[:i] + arg[eol+1:]
+	}
+}
+
+type funcNop struct{ expr string }
+
+func (f *funcNop) Arity() int                 { return 0 }
+func (f *funcNop) AddArg(Value)               {}
+func (f *funcNop) String() string             { return f.expr }
+func (f *funcNop) Eval(io.Writer, *Evaluator) {}
+
 // http://www.gnu.org/software/make/manual/make.html#Origin-Function
 type funcOrigin struct{ fclosure }